diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp
index 8a15a0d49117e4d085f75c467d7bddd1ad0a1ec6..d41cff1692f25207d9d1385e392cf39dfb370fe6 100644
--- a/source/App/DecoderApp/DecApp.cpp
+++ b/source/App/DecoderApp/DecApp.cpp
@@ -270,6 +270,13 @@ uint32_t DecApp::decode()
         xWriteOutput( pcListPic, nalu.m_temporalId );
       }
     }
+#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
+    if (bNewPicture || !bitstreamFile || nalu.m_nalUnitType == NAL_UNIT_EOS)
+    {
+      m_cDecLib.checkAPSInPictureUnit();
+      m_cDecLib.resetPictureUnitNals();
+    }
+#endif
     if(bNewAccessUnit)
     {
       m_cDecLib.checkTidLayerIdInAccessUnit();
diff --git a/source/Lib/CommonLib/NAL.h b/source/Lib/CommonLib/NAL.h
index 9e167bc790e85c3c2fc1cf49af324a887f54442c..f1605ce725c92e8e4d338817bd38a5c2a3155495 100644
--- a/source/Lib/CommonLib/NAL.h
+++ b/source/Lib/CommonLib/NAL.h
@@ -101,6 +101,24 @@ struct NALUnit
         || m_nalUnitType == NAL_UNIT_SUFFIX_SEI;
   }
 
+#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
+  bool isVcl()
+  {
+    return isVclNalUnitType(m_nalUnitType);
+  }
+
+  static bool isVclNalUnitType(NalUnitType t)
+  {
+    return t == NAL_UNIT_CODED_SLICE_TRAIL
+        || t == NAL_UNIT_CODED_SLICE_STSA
+        || t == NAL_UNIT_CODED_SLICE_RADL
+        || t == NAL_UNIT_CODED_SLICE_RASL
+        || t == NAL_UNIT_CODED_SLICE_IDR_W_RADL
+        || t == NAL_UNIT_CODED_SLICE_IDR_N_LP
+        || t == NAL_UNIT_CODED_SLICE_CRA
+        || t == NAL_UNIT_CODED_SLICE_GDR;
+  }
+#else
   bool isVcl()
   {
     return m_nalUnitType == NAL_UNIT_CODED_SLICE_TRAIL
@@ -112,6 +130,7 @@ struct NALUnit
         || m_nalUnitType == NAL_UNIT_CODED_SLICE_CRA
         || m_nalUnitType == NAL_UNIT_CODED_SLICE_GDR;
   }
+#endif
 };
 
 struct OutputNALUnit;
diff --git a/source/Lib/CommonLib/ParameterSetManager.h b/source/Lib/CommonLib/ParameterSetManager.h
index 1824d492eee203f1dd974eb5aac8540aafc75efb..40d5a9ddfdc4685aa1c14941a39a4505bf3818b4 100644
--- a/source/Lib/CommonLib/ParameterSetManager.h
+++ b/source/Lib/CommonLib/ParameterSetManager.h
@@ -137,7 +137,21 @@ public:
     {
       CHECK( m_paramsetMap.find( apsId ) == m_paramsetMap.end(), "APS does not exist" );
       APS* existedAPS = m_paramsetMap[apsId].parameterSet;
-
+#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
+      bool sameNalUnitType = aps->getHasPrefixNalUnitType() == existedAPS->getHasPrefixNalUnitType();
+      if( aps->getAPSType() == LMCS_APS )
+      {
+        CHECK( sameNalUnitType && aps->getReshaperAPSInfo() != existedAPS->getReshaperAPSInfo(), "All APS NAL units with a particular value of nal_unit_type, a particular value of aps_adaptation_parameter_set_id, and a particular value of aps_params_type within a PU shall have the same content" );
+      }
+      else if( aps->getAPSType() == ALF_APS )
+      {
+        CHECK( sameNalUnitType && aps->getAlfAPSParam() != existedAPS->getAlfAPSParam(), "All APS NAL units with a particular value of nal_unit_type, a particular value of aps_adaptation_parameter_set_id, and a particular value of aps_params_type within a PU shall have the same content" );
+      }
+      else if( aps->getAPSType() == SCALING_LIST_APS )
+      {
+        CHECK( sameNalUnitType && aps->getScalingList() != existedAPS->getScalingList(), "All APS NAL units with a particular value of nal_unit_type, a particular value of aps_adaptation_parameter_set_id, and a particular value of aps_params_type within a PU shall have the same content" );
+      }
+#else
       if( aps->getAPSType() == LMCS_APS )
       {
         CHECK( aps->getReshaperAPSInfo() != existedAPS->getReshaperAPSInfo(), "All APS NAL units with a particular value of adaptation_parameter_set_id and a particular value of aps_params_type within an access unit shall have the same content" );
@@ -150,6 +164,7 @@ public:
       {
         CHECK( aps->getScalingList() != existedAPS->getScalingList(), "All APS NAL units with a particular value of adaptation_parameter_set_id and a particular value of aps_params_type within an access unit shall have the same content" );
       }
+#endif
       else
       {
         CHECK( true, "Wrong APS type" );
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index 65f2870b61bfeede0414a2f5f0bd6afcbfd38ace..c5ffa434b32fcfe610e5cd8f1aa38d2b809641be 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -2108,6 +2108,9 @@ private:
   SliceReshapeInfo       m_reshapeAPSInfo;
   ScalingList            m_scalingListApsInfo;
   CcAlfFilterParam       m_ccAlfAPSParam;
+#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
+  bool                   m_hasPrefixNalUnitType;
+#endif
 
 public:
   APS();
@@ -2132,7 +2135,12 @@ public:
   ScalingList&           getScalingList()                                                 { return m_scalingListApsInfo;                  }
   void                   setCcAlfAPSParam(CcAlfFilterParam& ccAlfAPSParam)                { m_ccAlfAPSParam = ccAlfAPSParam;              }
   CcAlfFilterParam&      getCcAlfAPSParam()  { return m_ccAlfAPSParam; }
+#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
+  void                   setHasPrefixNalUnitType( bool b )                                { m_hasPrefixNalUnitType = b;                   }
+  bool                   getHasPrefixNalUnitType() const                                  { return m_hasPrefixNalUnitType;                }
+#endif
 };
+
 struct WPScalingParam
 {
   // Explicit weighted prediction parameters parsed in slice header,
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 0cb65647e1339579c0d9b929515296f7227456a7..e05227c83c9c18b539c2fb630a8ab0eb37bdbb28 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -89,6 +89,8 @@
 
 #define JVET_R0202_WHEN_PH_IN_SH_INFO_FLAGS_EQUAL_0       1 // JVET-R0202 When sh_picture_header_in_slice_header_flag is equal to 1, rpl_info_in_ph_flag, dbf_info_in_ph_flag, sao_info_in_ph_flag, wp_info_in_ph_flag, qp_delta_info_in_ph_flag shall be be equal to 0
 
+#define JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP              1 // JVET-R0201 Cleanups on Prefix and Suffix APS
+
 #define JVET_R0202_WHEN_PH_IN_SH_NO_SUBPIC_SEPARATE_COLOR 1 // JVET-R0202 Add constraints when sh_picture_header_in_slice_header_flag equal to 1 sps_subpic_info_present_flag and separate_colour_plane_flag shall be equal to 0
 
 #define JVET_R0247_PPS_LP_FTR_ACROSS_SLICES_FLAG_CLEANUP  1 // JVET-R0247: Skip pps_loop_filter_across_slices_enabled_flag when the picture contains one slice
diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index 34cf9a3344b0572e6496849cbac745cb62e0dace..3b0ea52c9ffeeb99cd4c3108d498244616056cb0 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -978,6 +978,30 @@ bool DecLib::isSliceNaluFirstInAU( bool newPicture, InputNALUnit &nalu )
   return (m_apcSlicePilot->getPOC() != m_prevPOC);
 }
 
+#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
+void DecLib::checkAPSInPictureUnit()
+{
+  bool firstVCLFound = false;
+  bool suffixAPSFound = false;
+  for (auto &nalu : m_pictureUnitNals)
+  {
+    if (NALUnit::isVclNalUnitType(nalu))
+    {
+      firstVCLFound = true;
+      CHECK( suffixAPSFound, "When any suffix APS NAL units are present in a PU, they shall follow the last VCL unit of the PU" );
+    }
+    else if (nalu == NAL_UNIT_PREFIX_APS)
+    {
+      CHECK( firstVCLFound, "When any prefix APS NAL units are present in a PU, they shall precede the first VCL unit of the PU");
+    }
+    else if (nalu == NAL_UNIT_SUFFIX_APS)
+    {
+      suffixAPSFound = true;
+    }
+  }
+}
+#endif
+
 void activateAPS(PicHeader* picHeader, Slice* pSlice, ParameterSetManager& parameterSetManager, APS** apss, APS* lmcsAPS, APS* scalingListAPS)
 {
 #if JVET_R0232_CCALF_APS_CONSTRAINT
@@ -2177,6 +2201,9 @@ void DecLib::xDecodeAPS(InputNALUnit& nalu)
   m_HLSReader.parseAPS(aps);
   aps->setTemporalId(nalu.m_temporalId);
   aps->setLayerId( nalu.m_nuhLayerId );
+#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
+  aps->setHasPrefixNalUnitType( nalu.m_nalUnitType == NAL_UNIT_PREFIX_APS );
+#endif
   m_parameterSetManager.checkAuApsContent( aps, m_accessUnitApsNals );
 
   // aps will be deleted if it was already stored (and did not changed),
@@ -2189,7 +2216,9 @@ bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay, i
   // ignore all NAL units of layers > 0
 
   m_accessUnitNals.push_back( std::pair<NalUnitType, int>( nalu.m_nalUnitType, nalu.m_temporalId ) );
-
+#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
+  m_pictureUnitNals.push_back( nalu.m_nalUnitType );
+#endif
   switch (nalu.m_nalUnitType)
   {
     case NAL_UNIT_VPS:
diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h
index c7ec5006f9dced19b86c08a2cfb28a2ebd635d8b..1b18ad0a03dad36adb18db8a57e47c3145932977 100644
--- a/source/Lib/DecoderLib/DecLib.h
+++ b/source/Lib/DecoderLib/DecLib.h
@@ -156,6 +156,11 @@ private:
 
   // NAL unit type, layer ID, and SEI payloadType
   std::vector<std::tuple<NalUnitType, int, SEI::PayloadType>> m_accessUnitSeiPayLoadTypes;
+
+#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
+  std::vector<NalUnitType> m_pictureUnitNals;
+#endif
+
   VPS*                    m_vps;
   int                     m_maxDecSubPicIdx;
   int                     m_maxDecSliceAddrInSubPic;
@@ -211,6 +216,11 @@ public:
   void checkSEIInAccessUnit();
   bool isSliceNaluFirstInAU( bool newPicture, InputNALUnit &nalu );
 
+#if JVET_R0201_PREFIX_SUFFIX_APS_CLEANUP
+  void checkAPSInPictureUnit();
+  void resetPictureUnitNals() { m_pictureUnitNals.clear(); }
+#endif
+
   const VPS* getVPS()                     { return m_vps; }
   void deriveTargetOutputLayerSet( const int targetOlsIdx ) { if( m_vps != nullptr ) m_vps->deriveTargetOutputLayerSet( targetOlsIdx ); }