diff --git a/include/opus.h b/include/opus.h
index ccf3e20159a7c34f4697faca16ac48c7eaa194a4..623662d5cc5b2f9c3d85f21ea793a9253e70956b 100644
--- a/include/opus.h
+++ b/include/opus.h
@@ -451,7 +451,10 @@ OPUS_EXPORT int opus_decoder_init(
   *  is frame_size*channels*sizeof(opus_int16)
   * @param [in] frame_size Number of samples per channel of available space in \a pcm.
   *  If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
-  *  not be capable of decoding some packets.
+  *  not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
+  *  then frame_size needs to be exactly the duration of audio that is missing, otherwise the
+  *  decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
+  *  FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.
   * @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be
   *  decoded. If no such data is available, the frame is decoded as if it were lost.
   * @returns Number of decoded samples or @ref opus_errorcodes
@@ -473,7 +476,10 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode(
   *  is frame_size*channels*sizeof(float)
   * @param [in] frame_size Number of samples per channel of available space in \a pcm.
   *  If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
-  *  not be capable of decoding some packets.
+  *  not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
+  *  then frame_size needs to be exactly the duration of audio that is missing, otherwise the
+  *  decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
+  *  FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.
   * @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be
   *  decoded. If no such data is available the frame is decoded as if it were lost.
   * @returns Number of decoded samples or @ref opus_errorcodes
diff --git a/include/opus_multistream.h b/include/opus_multistream.h
index bd816b4599850c797f6fce11ddcfb10c470ce03b..658067f7f1c579bd67542cfe3468ee5d47548aca 100644
--- a/include/opus_multistream.h
+++ b/include/opus_multistream.h
@@ -541,7 +541,12 @@ OPUS_EXPORT int opus_multistream_decoder_init(
   *                                 available space in \a pcm.
   *                                 If this is less than the maximum packet duration
   *                                 (120 ms; 5760 for 48kHz), this function will not be capable
-  *                                 of decoding some packets.
+  *                                 of decoding some packets. In the case of PLC (data==NULL)
+  *                                 or FEC (decode_fec=1), then frame_size needs to be exactly
+  *                                 the duration of audio that is missing, otherwise the
+  *                                 decoder will not be in the optimal state to decode the
+  *                                 next incoming packet. For the PLC and FEC cases, frame_size
+  *                                 <b>must</b> be a multiple of 2.5 ms.
   * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band
   *                                 forward error correction data be decoded.
   *                                 If no such data is available, the frame is
@@ -574,7 +579,12 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode(
   *                                 available space in \a pcm.
   *                                 If this is less than the maximum packet duration
   *                                 (120 ms; 5760 for 48kHz), this function will not be capable
-  *                                 of decoding some packets.
+  *                                 of decoding some packets. In the case of PLC (data==NULL)
+  *                                 or FEC (decode_fec=1), then frame_size needs to be exactly
+  *                                 the duration of audio that is missing, otherwise the
+  *                                 decoder will not be in the optimal state to decode the
+  *                                 next incoming packet. For the PLC and FEC cases, frame_size
+  *                                 <b>must</b> be a multiple of 2.5 ms.
   * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band
   *                                 forward error correction data be decoded.
   *                                 If no such data is available, the frame is
diff --git a/src/opus_decoder.c b/src/opus_decoder.c
index f0af5e746a13142340c33dee6f18511fdff55a7e..98de210ab178852e1b9dc6a3504b04e37751174d 100644
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -263,23 +263,10 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
       }
    }
 
-   /* For CELT/hybrid PLC of more than 20 ms, do multiple calls */
-   if (data==NULL && frame_size > F20 && mode != MODE_SILK_ONLY)
-   {
-      int nb_samples = 0;
-      do {
-         int ret = opus_decode_frame(st, NULL, 0, pcm, F20, 0);
-         if (ret != F20)
-         {
-            RESTORE_STACK;
-            return OPUS_INTERNAL_ERROR;
-         }
-         pcm += F20*st->channels;
-         nb_samples += F20;
-      } while (nb_samples < frame_size);
-      RESTORE_STACK;
-      return frame_size;
-   }
+   /* For CELT/hybrid PLC of more than 20 ms, opus_decode_native() will do
+      multiple calls */
+   if (data==NULL  && mode != MODE_SILK_ONLY)
+      frame_size = IMIN(frame_size, F20);
 
    pcm_transition_silk_size = 0;
    pcm_transition_celt_size = 0;
@@ -743,26 +730,68 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
    int count, offset;
    unsigned char toc;
    int tot_offset;
+   int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels;
    /* 48 x 2.5 ms = 120 ms */
    short size[48];
    if (decode_fec<0 || decode_fec>1)
       return OPUS_BAD_ARG;
+   /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
+   if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0)
+      return OPUS_BAD_ARG;
    if (len==0 || data==NULL)
-      return opus_decode_frame(st, NULL, 0, pcm, frame_size, 0);
-   else if (len<0)
+   {
+      int pcm_count=0;
+      do {
+         int ret;
+         ret = opus_decode_frame(st, NULL, 0, pcm, frame_size-pcm_count, 0);
+         if (ret<0)
+            return ret;
+         pcm += st->channels*ret;
+         pcm_count += ret;
+      } while (pcm_count < frame_size);
+      return pcm_count;
+   } else if (len<0)
       return OPUS_BAD_ARG;
 
-   tot_offset = 0;
-   st->mode = opus_packet_get_mode(data);
-   st->bandwidth = opus_packet_get_bandwidth(data);
-   st->frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
-   st->stream_channels = opus_packet_get_nb_channels(data);
+   packet_mode = opus_packet_get_mode(data);
+   packet_bandwidth = opus_packet_get_bandwidth(data);
+   packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
+   packet_stream_channels = opus_packet_get_nb_channels(data);
 
    count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset);
+
+   data += offset;
+
+   if (decode_fec)
+   {
+      int ret;
+      /* If no FEC can be present, run the PLC (recursive call) */
+      if (frame_size <= packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY)
+         return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL);
+      /* Otherwise, run the PLC on everything except the size for which we might have FEC */
+      ret = opus_decode_frame(st, NULL, 0, pcm, frame_size-packet_frame_size, 0);
+      if (ret<0)
+         return ret;
+      /* Complete with FEC */
+      st->mode = packet_mode;
+      st->bandwidth = packet_bandwidth;
+      st->frame_size = packet_frame_size;
+      st->stream_channels = packet_stream_channels;
+      ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size),
+            packet_frame_size, 1);
+      if (ret<0)
+         return ret;
+      else
+         return frame_size;
+   }
+   tot_offset = 0;
+   st->mode = packet_mode;
+   st->bandwidth = packet_bandwidth;
+   st->frame_size = packet_frame_size;
+   st->stream_channels = packet_stream_channels;
    if (count < 0)
       return count;
 
-   data += offset;
    tot_offset += offset;
 
    if (count*st->frame_size > frame_size)
diff --git a/tests/test_opus_decode.c b/tests/test_opus_decode.c
index 868869b9e63e8167a9217ccc595885fb9861f744..be93df4844220d4bc26b6a5cb07e7af4452c328e 100644
--- a/tests/test_opus_decode.c
+++ b/tests/test_opus_decode.c
@@ -106,21 +106,21 @@ int test_decoder_code0(int no_fuzz)
       for(fec=0;fec<2;fec++)
       {
          /*Test PLC on a fresh decoder*/
-         out_samples = opus_decode(dec[t], 0, 0, outbuf, MAX_FRAME_SAMP, fec);
+         out_samples = opus_decode(dec[t], 0, 0, outbuf, 120/factor, fec);
          if(out_samples!=120/factor)test_failed();
 
          /*Test null pointer input*/
-         out_samples = opus_decode(dec[t], 0, -1, outbuf, MAX_FRAME_SAMP, fec);
+         out_samples = opus_decode(dec[t], 0, -1, outbuf, 120/factor, fec);
          if(out_samples!=120/factor)test_failed();
-         out_samples = opus_decode(dec[t], 0, 1, outbuf, MAX_FRAME_SAMP, fec);
+         out_samples = opus_decode(dec[t], 0, 1, outbuf, 120/factor, fec);
          if(out_samples!=120/factor)test_failed();
-         out_samples = opus_decode(dec[t], 0, 10, outbuf, MAX_FRAME_SAMP, fec);
+         out_samples = opus_decode(dec[t], 0, 10, outbuf, 120/factor, fec);
          if(out_samples!=120/factor)test_failed();
-         out_samples = opus_decode(dec[t], 0, fast_rand(), outbuf, MAX_FRAME_SAMP, fec);
+         out_samples = opus_decode(dec[t], 0, fast_rand(), outbuf, 120/factor, fec);
          if(out_samples!=120/factor)test_failed();
 
          /*Zero lengths*/
-         out_samples = opus_decode(dec[t], packet, 0, outbuf, MAX_FRAME_SAMP, fec);
+         out_samples = opus_decode(dec[t], packet, 0, outbuf, 120/factor, fec);
          if(out_samples!=120/factor)test_failed();
 
          /*Zero buffer*/
@@ -182,7 +182,7 @@ int test_decoder_code0(int no_fuzz)
          /* The PLC is run for 6 frames in order to get better PLC coverage. */
          for(j=0;j<6;j++)
          {
-            out_samples = opus_decode(dec[t], 0, 0, outbuf, MAX_FRAME_SAMP, 0);
+            out_samples = opus_decode(dec[t], 0, 0, outbuf, expected[t], 0);
             if(out_samples!=expected[t])test_failed();
          }
          /* Run the PLC once at 2.5ms, as a simulation of someone trying to
@@ -292,7 +292,7 @@ int test_decoder_code0(int no_fuzz)
       for(t=0;t<5*2;t++)expected[t]=opus_decoder_get_nb_samples(dec[t],packet,plen);
       for(j=0;j<plen;j++)packet[j+1]=(fast_rand()|fast_rand())&255;
       memcpy(decbak,dec[0],decsize);
-      if(opus_decode(decbak, packet, plen+1, outbuf, MAX_FRAME_SAMP, 1)!=expected[0])test_failed();
+      if(opus_decode(decbak, packet, plen+1, outbuf, expected[0], 1)!=expected[0])test_failed();
       memcpy(decbak,dec[0],decsize);
       if(opus_decode(decbak,  0, 0, outbuf, MAX_FRAME_SAMP, 1)<20)test_failed();
       memcpy(decbak,dec[0],decsize);
diff --git a/tests/test_opus_encode.c b/tests/test_opus_encode.c
index 61e0dec18f18d49d093bf2b0ee6667790690b29f..b80def3f64a1ec8bf40dd42cb582d010b5c67d55 100644
--- a/tests/test_opus_encode.c
+++ b/tests/test_opus_encode.c
@@ -269,7 +269,7 @@ int run_test1(int no_fuzz)
             if(opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range))!=OPUS_OK)test_failed();
             if(enc_final_range!=dec_final_range)test_failed();
             /*LBRR decode*/
-            out_samples = opus_decode(dec_err[0], packet, len, out2buf, MAX_FRAME_SAMP, (fast_rand()&3)!=0);
+            out_samples = opus_decode(dec_err[0], packet, len, out2buf, frame_size, (fast_rand()&3)!=0);
             if(out_samples!=frame_size)test_failed();
             out_samples = opus_decode(dec_err[1], packet, (fast_rand()&3)==0?0:len, out2buf, MAX_FRAME_SAMP, (fast_rand()&7)!=0);
             if(out_samples<120)test_failed();
@@ -317,8 +317,8 @@ int run_test1(int no_fuzz)
             if(enc_final_range!=dec_final_range)test_failed();
             /*LBRR decode*/
             loss=(fast_rand()&63)==0;
-            out_samples = opus_multistream_decode(MSdec_err, packet, loss?0:len, out2buf, MAX_FRAME_SAMP, (fast_rand()&3)!=0);
-            if(loss?out_samples<120:out_samples!=(frame_size*6))test_failed();
+            out_samples = opus_multistream_decode(MSdec_err, packet, loss?0:len, out2buf, frame_size*6, (fast_rand()&3)!=0);
+            if(out_samples!=(frame_size*6))test_failed();
             i+=frame_size;
             count++;
          }while(i<(SSAMPLES/12-MAX_FRAME_SAMP));