diff --git a/libavresample/audio_mix.c b/libavresample/audio_mix.c
index dd2f33d27fe3ac98c1b4b67e21bdc1a3690a540d..3b39ceeca5777b4826260339d20117c31cae0546 100644
--- a/libavresample/audio_mix.c
+++ b/libavresample/audio_mix.c
@@ -302,27 +302,37 @@ static int mix_function_init(AudioMix *am)
     return 0;
 }
 
-int ff_audio_mix_init(AVAudioResampleContext *avr)
+AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
 {
+    AudioMix *am;
     int ret;
 
+    am = av_mallocz(sizeof(*am));
+    if (!am)
+        return NULL;
+    am->avr = avr;
+
     if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P &&
         avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) {
         av_log(avr, AV_LOG_ERROR, "Unsupported internal format for "
                "mixing: %s\n",
                av_get_sample_fmt_name(avr->internal_sample_fmt));
-        return AVERROR(EINVAL);
+        goto error;
     }
 
+    am->fmt          = avr->internal_sample_fmt;
+    am->coeff_type   = avr->mix_coeff_type;
+    am->in_layout    = avr->in_channel_layout;
+    am->out_layout   = avr->out_channel_layout;
+    am->in_channels  = avr->in_channels;
+    am->out_channels = avr->out_channels;
+
     /* build matrix if the user did not already set one */
-    if (avr->am->matrix) {
-        if (avr->am->coeff_type != avr->mix_coeff_type      ||
-            avr->am->in_layout  != avr->in_channel_layout   ||
-            avr->am->out_layout != avr->out_channel_layout) {
-            av_log(avr, AV_LOG_ERROR,
-                   "Custom matrix does not match current parameters\n");
-            return AVERROR(EINVAL);
-        }
+    if (avr->mix_matrix) {
+        ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_channels);
+        if (ret < 0)
+            goto error;
+        av_freep(&avr->mix_matrix);
     } else {
         int i, j;
         char in_layout_name[128];
@@ -330,7 +340,7 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
         double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels *
                                         sizeof(*matrix_dbl));
         if (!matrix_dbl)
-            return AVERROR(ENOMEM);
+            goto error;
 
         ret = avresample_build_matrix(avr->in_channel_layout,
                                       avr->out_channel_layout,
@@ -343,7 +353,7 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
                                       avr->matrix_encoding);
         if (ret < 0) {
             av_free(matrix_dbl);
-            return ret;
+            goto error;
         }
 
         av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name),
@@ -360,32 +370,33 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
             av_log(avr, AV_LOG_DEBUG, "\n");
         }
 
-        ret = avresample_set_matrix(avr, matrix_dbl, avr->in_channels);
+        ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels);
         if (ret < 0) {
             av_free(matrix_dbl);
-            return ret;
+            goto error;
         }
         av_free(matrix_dbl);
     }
 
-    avr->am->fmt          = avr->internal_sample_fmt;
-    avr->am->coeff_type   = avr->mix_coeff_type;
-    avr->am->in_layout    = avr->in_channel_layout;
-    avr->am->out_layout   = avr->out_channel_layout;
-    avr->am->in_channels  = avr->in_channels;
-    avr->am->out_channels = avr->out_channels;
-
-    ret = mix_function_init(avr->am);
+    ret = mix_function_init(am);
     if (ret < 0)
-        return ret;
+        goto error;
 
-    return 0;
+    return am;
+
+error:
+    av_free(am);
+    return NULL;
 }
 
-void ff_audio_mix_close(AudioMix *am)
+void ff_audio_mix_free(AudioMix **am_p)
 {
-    if (!am)
+    AudioMix *am;
+
+    if (!*am_p)
         return;
+    am = *am_p;
+
     if (am->matrix) {
         av_free(am->matrix[0]);
         am->matrix = NULL;
@@ -393,6 +404,8 @@ void ff_audio_mix_close(AudioMix *am)
     memset(am->matrix_q8,  0, sizeof(am->matrix_q8 ));
     memset(am->matrix_q15, 0, sizeof(am->matrix_q15));
     memset(am->matrix_flt, 0, sizeof(am->matrix_flt));
+
+    av_freep(am_p);
 }
 
 int ff_audio_mix(AudioMix *am, AudioData *src)
@@ -424,3 +437,92 @@ int ff_audio_mix(AudioMix *am, AudioData *src)
 
     return 0;
 }
+
+int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride)
+{
+    int i, o;
+
+    if ( am->in_channels <= 0 ||  am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
+        am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
+        av_log(am, AV_LOG_ERROR, "Invalid channel counts\n");
+        return AVERROR(EINVAL);
+    }
+
+#define GET_MATRIX_CONVERT(suffix, scale)                                   \
+    if (!am->matrix_ ## suffix[0]) {                                        \
+        av_log(am, AV_LOG_ERROR, "matrix is not set\n");                    \
+        return AVERROR(EINVAL);                                             \
+    }                                                                       \
+    for (o = 0; o < am->out_channels; o++)                                  \
+        for (i = 0; i < am->in_channels; i++)                               \
+            matrix[o * stride + i] = am->matrix_ ## suffix[o][i] * (scale);
+
+    switch (am->coeff_type) {
+    case AV_MIX_COEFF_TYPE_Q8:
+        GET_MATRIX_CONVERT(q8, 1.0 / 256.0);
+        break;
+    case AV_MIX_COEFF_TYPE_Q15:
+        GET_MATRIX_CONVERT(q15, 1.0 / 32768.0);
+        break;
+    case AV_MIX_COEFF_TYPE_FLT:
+        GET_MATRIX_CONVERT(flt, 1.0);
+        break;
+    default:
+        av_log(am, AV_LOG_ERROR, "Invalid mix coeff type\n");
+        return AVERROR(EINVAL);
+    }
+
+    return 0;
+}
+
+int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride)
+{
+    int i, o;
+
+    if ( am->in_channels <= 0 ||  am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
+        am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
+        av_log(am, AV_LOG_ERROR, "Invalid channel counts\n");
+        return AVERROR(EINVAL);
+    }
+
+    if (am->matrix) {
+        av_free(am->matrix[0]);
+        am->matrix = NULL;
+    }
+
+#define CONVERT_MATRIX(type, expr)                                          \
+    am->matrix_## type[0] = av_mallocz(am->out_channels * am->in_channels * \
+                                       sizeof(*am->matrix_## type[0]));     \
+    if (!am->matrix_## type[0])                                             \
+        return AVERROR(ENOMEM);                                             \
+    for (o = 0; o < am->out_channels; o++) {                                \
+        if (o > 0)                                                          \
+            am->matrix_## type[o] = am->matrix_## type[o - 1] +             \
+                                    am->in_channels;                        \
+        for (i = 0; i < am->in_channels; i++) {                             \
+            double v = matrix[o * stride + i];                              \
+            am->matrix_## type[o][i] = expr;                                \
+        }                                                                   \
+    }                                                                       \
+    am->matrix = (void **)am->matrix_## type;
+
+    switch (am->coeff_type) {
+    case AV_MIX_COEFF_TYPE_Q8:
+        CONVERT_MATRIX(q8, av_clip_int16(lrint(256.0 * v)))
+        break;
+    case AV_MIX_COEFF_TYPE_Q15:
+        CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v)))
+        break;
+    case AV_MIX_COEFF_TYPE_FLT:
+        CONVERT_MATRIX(flt, v)
+        break;
+    default:
+        av_log(am, AV_LOG_ERROR, "Invalid mix coeff type\n");
+        return AVERROR(EINVAL);
+    }
+
+    /* TODO: detect situations where we can just swap around pointers
+             instead of doing matrix multiplications with 0.0 and 1.0 */
+
+    return 0;
+}
diff --git a/libavresample/audio_mix.h b/libavresample/audio_mix.h
index 2199fffe0ece9a6d61017a1e71ada7012b86726f..22faea7c1becb9685fad30786c9cf7a00d4ba295 100644
--- a/libavresample/audio_mix.h
+++ b/libavresample/audio_mix.h
@@ -79,28 +79,36 @@ void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt,
                            const char *descr, void *mix_func);
 
 /**
- * Initialize the AudioMix context in the AVAudioResampleContext.
+ * Allocate and initialize an AudioMix context.
  *
  * The parameters in the AVAudioResampleContext are used to initialize the
- * AudioMix context and set the mixing matrix.
+ * AudioMix context.
  *
  * @param avr  AVAudioResampleContext
- * @return     0 on success, negative AVERROR code on failure
+ * @return     newly-allocated AudioMix context.
  */
-int ff_audio_mix_init(AVAudioResampleContext *avr);
+AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr);
 
 /**
- * Close an AudioMix context.
- *
- * This clears and frees the mixing matrix arrays.
+ * Free an AudioMix context.
  */
-void ff_audio_mix_close(AudioMix *am);
+void ff_audio_mix_free(AudioMix **am);
 
 /**
  * Apply channel mixing to audio data using the current mixing matrix.
  */
 int ff_audio_mix(AudioMix *am, AudioData *src);
 
+/**
+ * Get the current mixing matrix.
+ */
+int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride);
+
+/**
+ * Set the current mixing matrix.
+ */
+int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride);
+
 /* arch-specific initialization functions */
 
 void ff_audio_mix_init_x86(AudioMix *am);
diff --git a/libavresample/audio_mix_matrix.c b/libavresample/audio_mix_matrix.c
index 01a93367ef393f829408ce6d3b40e1c5c902ac1a..8da1b487a40e2bdb565c8df843483efb5e843af6 100644
--- a/libavresample/audio_mix_matrix.c
+++ b/libavresample/audio_mix_matrix.c
@@ -287,115 +287,3 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout,
 
     return 0;
 }
-
-int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
-                          int stride)
-{
-    int in_channels, out_channels, i, o;
-
-    in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout);
-    out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
-
-    if ( in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS ||
-        out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
-        av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
-        return AVERROR(EINVAL);
-    }
-
-    switch (avr->mix_coeff_type) {
-    case AV_MIX_COEFF_TYPE_Q8:
-        if (!avr->am->matrix_q8[0]) {
-            av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
-            return AVERROR(EINVAL);
-        }
-        for (o = 0; o < out_channels; o++)
-            for (i = 0; i < in_channels; i++)
-                matrix[o * stride + i] = avr->am->matrix_q8[o][i] / 256.0;
-        break;
-    case AV_MIX_COEFF_TYPE_Q15:
-        if (!avr->am->matrix_q15[0]) {
-            av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
-            return AVERROR(EINVAL);
-        }
-        for (o = 0; o < out_channels; o++)
-            for (i = 0; i < in_channels; i++)
-                matrix[o * stride + i] = avr->am->matrix_q15[o][i] / 32768.0;
-        break;
-    case AV_MIX_COEFF_TYPE_FLT:
-        if (!avr->am->matrix_flt[0]) {
-            av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
-            return AVERROR(EINVAL);
-        }
-        for (o = 0; o < out_channels; o++)
-            for (i = 0; i < in_channels; i++)
-                matrix[o * stride + i] = avr->am->matrix_flt[o][i];
-        break;
-    default:
-        av_log(avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
-        return AVERROR(EINVAL);
-    }
-
-    return 0;
-}
-
-int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
-                          int stride)
-{
-    int in_channels, out_channels, i, o;
-
-    in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout);
-    out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
-
-    if ( in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS ||
-        out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
-        av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
-        return AVERROR(EINVAL);
-    }
-
-    if (avr->am->matrix) {
-        av_free(avr->am->matrix[0]);
-        avr->am->matrix = NULL;
-    }
-
-#define CONVERT_MATRIX(type, expr)                                          \
-    avr->am->matrix_## type[0] = av_mallocz(out_channels * in_channels *    \
-                                            sizeof(*avr->am->matrix_## type[0])); \
-    if (!avr->am->matrix_## type[0])                                        \
-        return AVERROR(ENOMEM);                                             \
-    for (o = 0; o < out_channels; o++) {                                    \
-        if (o > 0)                                                          \
-            avr->am->matrix_## type[o] = avr->am->matrix_## type[o - 1] +   \
-                                         in_channels;                       \
-        for (i = 0; i < in_channels; i++) {                                 \
-            double v = matrix[o * stride + i];                              \
-            avr->am->matrix_## type[o][i] = expr;                           \
-        }                                                                   \
-    }                                                                       \
-    avr->am->matrix = (void **)avr->am->matrix_## type;
-
-    switch (avr->mix_coeff_type) {
-    case AV_MIX_COEFF_TYPE_Q8:
-        CONVERT_MATRIX(q8, av_clip_int16(lrint(256.0 * v)))
-        break;
-    case AV_MIX_COEFF_TYPE_Q15:
-        CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v)))
-        break;
-    case AV_MIX_COEFF_TYPE_FLT:
-        CONVERT_MATRIX(flt, v)
-        break;
-    default:
-        av_log(avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
-        return AVERROR(EINVAL);
-    }
-
-    /* TODO: detect situations where we can just swap around pointers
-             instead of doing matrix multiplications with 0.0 and 1.0 */
-
-    /* set AudioMix params */
-    avr->am->in_layout    = avr->in_channel_layout;
-    avr->am->out_layout   = avr->out_channel_layout;
-    avr->am->in_channels  = in_channels;
-    avr->am->out_channels = out_channels;
-
-    return 0;
-}
diff --git a/libavresample/internal.h b/libavresample/internal.h
index 006b6fd14a9ca91e5b169ba3ac63f59e03cda1aa..3fd33fed6a043477a1da6e7b39691e45a4a07a67 100644
--- a/libavresample/internal.h
+++ b/libavresample/internal.h
@@ -74,6 +74,12 @@ struct AVAudioResampleContext {
     ResampleContext *resample;  /**< resampling context                      */
     AudioMix *am;               /**< channel mixing context                  */
     enum AVMatrixEncoding matrix_encoding;      /**< matrixed stereo encoding */
+
+    /**
+     * mix matrix
+     * only used if avresample_set_matrix() is called before avresample_open()
+     */
+    double *mix_matrix;
 };
 
 #endif /* AVRESAMPLE_INTERNAL_H */
diff --git a/libavresample/options.c b/libavresample/options.c
index 8f643700cbcc7dc2bc2e0918df2242e57aa871b0..824f5e3bc3b943f984b708d752c1d92e3bd2743c 100644
--- a/libavresample/options.c
+++ b/libavresample/options.c
@@ -84,13 +84,6 @@ AVAudioResampleContext *avresample_alloc_context(void)
     avr->av_class = &av_resample_context_class;
     av_opt_set_defaults(avr);
 
-    avr->am = av_mallocz(sizeof(*avr->am));
-    if (!avr->am) {
-        av_free(avr);
-        return NULL;
-    }
-    avr->am->avr = avr;
-
     return avr;
 }
 
diff --git a/libavresample/utils.c b/libavresample/utils.c
index 3fdeeb8cc0d0c44f696ab3e2d19af4242a8ca3b2..8245e6a3454faa6c7e6e5f4a87365f9dae9989e4 100644
--- a/libavresample/utils.c
+++ b/libavresample/utils.c
@@ -169,9 +169,11 @@ int avresample_open(AVAudioResampleContext *avr)
         }
     }
     if (avr->mixing_needed) {
-        ret = ff_audio_mix_init(avr);
-        if (ret < 0)
+        avr->am = ff_audio_mix_alloc(avr);
+        if (!avr->am) {
+            ret = AVERROR(ENOMEM);
             goto error;
+        }
     }
 
     return 0;
@@ -191,8 +193,8 @@ void avresample_close(AVAudioResampleContext *avr)
     av_freep(&avr->ac_in);
     av_freep(&avr->ac_out);
     ff_audio_resample_free(&avr->resample);
-    ff_audio_mix_close(avr->am);
-    return;
+    ff_audio_mix_free(&avr->am);
+    av_freep(&avr->mix_matrix);
 }
 
 void avresample_free(AVAudioResampleContext **avr)
@@ -200,7 +202,6 @@ void avresample_free(AVAudioResampleContext **avr)
     if (!*avr)
         return;
     avresample_close(*avr);
-    av_freep(&(*avr)->am);
     av_opt_free(*avr);
     av_freep(avr);
 }
@@ -404,6 +405,66 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
                                   current_buffer);
 }
 
+int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
+                          int stride)
+{
+    int in_channels, out_channels, i, o;
+
+    if (avr->am)
+        return ff_audio_mix_get_matrix(avr->am, matrix, stride);
+
+    in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout);
+    out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
+
+    if ( in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS ||
+        out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
+        av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
+        return AVERROR(EINVAL);
+    }
+
+    if (!avr->mix_matrix) {
+        av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
+        return AVERROR(EINVAL);
+    }
+
+    for (o = 0; o < out_channels; o++)
+        for (i = 0; i < in_channels; i++)
+            matrix[o * stride + i] = avr->mix_matrix[o * in_channels + i];
+
+    return 0;
+}
+
+int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
+                          int stride)
+{
+    int in_channels, out_channels, i, o;
+
+    if (avr->am)
+        return ff_audio_mix_set_matrix(avr->am, matrix, stride);
+
+    in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout);
+    out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
+
+    if ( in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS ||
+        out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
+        av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
+        return AVERROR(EINVAL);
+    }
+
+    if (avr->mix_matrix)
+        av_freep(&avr->mix_matrix);
+    avr->mix_matrix = av_malloc(in_channels * out_channels *
+                                sizeof(*avr->mix_matrix));
+    if (!avr->mix_matrix)
+        return AVERROR(ENOMEM);
+
+    for (o = 0; o < out_channels; o++)
+        for (i = 0; i < in_channels; i++)
+            avr->mix_matrix[o * in_channels + i] = matrix[o * stride + i];
+
+    return 0;
+}
+
 int avresample_available(AVAudioResampleContext *avr)
 {
     return av_audio_fifo_size(avr->out_fifo);