diff --git a/libavutil/frame.c b/libavutil/frame.c
index e4038096c2..600f82bbeb 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -267,18 +267,27 @@ fail:
 
 static int get_audio_buffer(AVFrame *frame, int align)
 {
-    int channels;
     int planar   = av_sample_fmt_is_planar(frame->format);
-    int planes;
+    int channels, planes;
     int ret, i;
 
-    if (!frame->channels)
-        frame->channels = av_get_channel_layout_nb_channels(frame->channel_layout);
-
-    channels = frame->channels;
-    planes = planar ? channels : 1;
-
-    CHECK_CHANNELS_CONSISTENCY(frame);
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+    if (!frame->ch_layout.nb_channels) {
+        if (frame->channel_layout) {
+            av_channel_layout_from_mask(&frame->ch_layout, frame->channel_layout);
+        } else {
+            frame->ch_layout.nb_channels = frame->channels;
+            frame->ch_layout.order       = AV_CHANNEL_ORDER_UNSPEC;
+        }
+    }
+    frame->channels = frame->ch_layout.nb_channels;
+    frame->channel_layout = frame->ch_layout.order == AV_CHANNEL_ORDER_NATIVE ?
+                            frame->ch_layout.u.mask : 0;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    channels = frame->ch_layout.nb_channels;
+    planes   = planar ? channels : 1;
     if (!frame->linesize[0]) {
         ret = av_samples_get_buffer_size(&frame->linesize[0], channels,
                                          frame->nb_samples, frame->format,
@@ -326,10 +335,17 @@ int av_frame_get_buffer(AVFrame *frame, int align)
     if (frame->format < 0)
         return AVERROR(EINVAL);
 
+FF_DISABLE_DEPRECATION_WARNINGS
     if (frame->width > 0 && frame->height > 0)
         return get_video_buffer(frame, align);
-    else if (frame->nb_samples > 0 && (frame->channel_layout || frame->channels > 0))
+    else if (frame->nb_samples > 0 &&
+             (av_channel_layout_check(&frame->ch_layout)
+#if FF_API_OLD_CHANNEL_LAYOUT
+              || frame->channel_layout || frame->channels > 0
+#endif
+             ))
         return get_audio_buffer(frame, align);
+FF_ENABLE_DEPRECATION_WARNINGS
 
     return AVERROR(EINVAL);
 }
@@ -450,14 +466,33 @@ int av_frame_ref(AVFrame *dst, const AVFrame *src)
     dst->format         = src->format;
     dst->width          = src->width;
     dst->height         = src->height;
+    dst->nb_samples     = src->nb_samples;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
     dst->channels       = src->channels;
     dst->channel_layout = src->channel_layout;
-    dst->nb_samples     = src->nb_samples;
+    if (!av_channel_layout_check(&src->ch_layout)) {
+        if (src->channel_layout)
+            av_channel_layout_from_mask(&dst->ch_layout, src->channel_layout);
+        else {
+            dst->ch_layout.nb_channels = src->channels;
+            dst->ch_layout.order       = AV_CHANNEL_ORDER_UNSPEC;
+        }
+    }
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
 
     ret = frame_copy_props(dst, src, 0);
     if (ret < 0)
         return ret;
 
+    // this check is needed only until FF_API_OLD_CHANNEL_LAYOUT is out
+    if (av_channel_layout_check(&src->ch_layout)) {
+        ret = av_channel_layout_copy(&dst->ch_layout, &src->ch_layout);
+        if (ret < 0)
+            goto fail;
+    }
+
     /* duplicate the frame data if it's not refcounted */
     if (!src->buf[0]) {
         ret = av_frame_get_buffer(dst, 32);
@@ -510,13 +545,12 @@ int av_frame_ref(AVFrame *dst, const AVFrame *src)
 
     /* duplicate extended data */
     if (src->extended_data != src->data) {
-        int ch = src->channels;
+        int ch = dst->ch_layout.nb_channels;
 
         if (!ch) {
             ret = AVERROR(EINVAL);
             goto fail;
         }
-        CHECK_CHANNELS_CONSISTENCY(src);
 
         dst->extended_data = av_malloc_array(sizeof(*dst->extended_data), ch);
         if (!dst->extended_data) {
@@ -576,6 +610,8 @@ FF_ENABLE_DEPRECATION_WARNINGS
     av_buffer_unref(&frame->opaque_ref);
     av_buffer_unref(&frame->private_ref);
 
+    av_channel_layout_uninit(&frame->ch_layout);
+
     get_frame_defaults(frame);
 }
 
@@ -623,9 +659,19 @@ int av_frame_make_writable(AVFrame *frame)
     tmp.format         = frame->format;
     tmp.width          = frame->width;
     tmp.height         = frame->height;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
     tmp.channels       = frame->channels;
     tmp.channel_layout = frame->channel_layout;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
     tmp.nb_samples     = frame->nb_samples;
+    ret = av_channel_layout_copy(&tmp.ch_layout, &frame->ch_layout);
+    if (ret < 0) {
+        av_frame_unref(&tmp);
+        return ret;
+    }
+
     ret = av_frame_get_buffer(&tmp, 32);
     if (ret < 0)
         return ret;
@@ -662,10 +708,16 @@ AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane)
     int planes, i;
 
     if (frame->nb_samples) {
-        int channels = frame->channels;
+        int channels = frame->ch_layout.nb_channels;
+
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+        if (!channels)
+            channels = av_get_channel_layout_nb_channels(frame->channel_layout);
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
         if (!channels)
             return NULL;
-        CHECK_CHANNELS_CONSISTENCY(frame);
         planes = av_sample_fmt_is_planar(frame->format) ? channels : 1;
     } else
         planes = 4;
@@ -768,14 +820,28 @@ static int frame_copy_video(AVFrame *dst, const AVFrame *src)
 static int frame_copy_audio(AVFrame *dst, const AVFrame *src)
 {
     int planar   = av_sample_fmt_is_planar(dst->format);
-    int channels = dst->channels;
+    int channels = dst->ch_layout.nb_channels;
     int planes   = planar ? channels : 1;
     int i;
 
-    if (dst->nb_samples     != src->nb_samples ||
-        dst->channels       != src->channels ||
-        dst->channel_layout != src->channel_layout)
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+    if (!channels) {
+        channels = av_get_channel_layout_nb_channels(dst->channel_layout);
+        planes = planar ? channels : 1;
+    }
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+FF_DISABLE_DEPRECATION_WARNINGS
+    if (dst->nb_samples != src->nb_samples ||
+        av_channel_layout_compare(&dst->ch_layout, &src->ch_layout)
+#if FF_API_OLD_CHANNEL_LAYOUT
+        || dst->channel_layout != src->channel_layout
+#endif
+        )
         return AVERROR(EINVAL);
+FF_ENABLE_DEPRECATION_WARNINGS
 
     CHECK_CHANNELS_CONSISTENCY(src);
 
@@ -794,10 +860,17 @@ int av_frame_copy(AVFrame *dst, const AVFrame *src)
     if (dst->format != src->format || dst->format < 0)
         return AVERROR(EINVAL);
 
+FF_DISABLE_DEPRECATION_WARNINGS
     if (dst->width > 0 && dst->height > 0)
         return frame_copy_video(dst, src);
-    else if (dst->nb_samples > 0 && dst->channels > 0)
+    else if (dst->nb_samples > 0 &&
+             (av_channel_layout_check(&dst->ch_layout)
+#if FF_API_OLD_CHANNEL_LAYOUT
+              || dst->channel_layout || dst->channels
+#endif
+            ))
         return frame_copy_audio(dst, src);
+FF_ENABLE_DEPRECATION_WARNINGS
 
     return AVERROR(EINVAL);
 }
diff --git a/libavutil/frame.h b/libavutil/frame.h
index b5afb58634..f9623ece20 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -30,6 +30,7 @@
 
 #include "avutil.h"
 #include "buffer.h"
+#include "channel_layout.h"
 #include "dict.h"
 #include "rational.h"
 #include "samplefmt.h"
@@ -466,10 +467,14 @@ typedef struct AVFrame {
      */
     int sample_rate;
 
+#if FF_API_OLD_CHANNEL_LAYOUT
     /**
      * Channel layout of the audio data.
+     * @deprecated use ch_layout instead
      */
+    attribute_deprecated
     uint64_t channel_layout;
+#endif
 
     /**
      * AVBuffer references backing the data for this frame. If all elements of
@@ -672,6 +677,11 @@ typedef struct AVFrame {
      * for the target frame's private_ref field.
      */
     AVBufferRef *private_ref;
+
+    /**
+     * Channel layout of the audio data.
+     */
+    AVChannelLayout ch_layout;
 } AVFrame;
 
 #if FF_API_FRAME_GET_SET
@@ -804,7 +814,7 @@ void av_frame_move_ref(AVFrame *dst, AVFrame *src);
  * The following fields must be set on frame before calling this function:
  * - format (pixel format for video, sample format for audio)
  * - width and height for video
- * - nb_samples and channel_layout for audio
+ * - nb_samples and ch_layout for audio
  *
  * This function will fill AVFrame.data and AVFrame.buf arrays and, if
  * necessary, allocate and fill AVFrame.extended_data and AVFrame.extended_buf.
