diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp
index 7ef205b856c9f01b64238b25a1723be2177ebce5..35534502401fc2287f763d4157f5fd25135ac681 100644
--- a/source/App/DecoderApp/DecApp.cpp
+++ b/source/App/DecoderApp/DecApp.cpp
@@ -124,6 +124,10 @@ uint32_t DecApp::decode()
 
   bool bPicSkipped = false;
 
+#if JVET_S0155_EOS_NALU_CHECK
+  bool isEosPresentInPu = false;
+#endif
+
   while (!!bitstreamFile)
   {
     InputNALUnit nalu;
@@ -194,6 +198,18 @@ uint32_t DecApp::decode()
           bPicSkipped = true;
         }
       }
+#if JVET_S0155_EOS_NALU_CHECK
+      // once an EOS NAL unit appears in the current PU, mark the variable isEosPresentInPu as true
+      if (nalu.m_nalUnitType == NAL_UNIT_EOS)
+      {
+        isEosPresentInPu = true;
+      }
+      // within the current PU, only EOS and EOB are allowed to be sent after an EOS nal unit
+      if(isEosPresentInPu)
+      {
+        CHECK(nalu.m_nalUnitType != NAL_UNIT_EOS && nalu.m_nalUnitType != NAL_UNIT_EOB, "When an EOS NAL unit is present in a PU, it shall be the last NAL unit among all NAL units within the PU other than other EOS NAL units or an EOB NAL unit");
+      }
+#endif
     }
 
     if ((bNewPicture || !bitstreamFile || nalu.m_nalUnitType == NAL_UNIT_EOS) && !m_cDecLib.getFirstSliceInSequence(nalu.m_nuhLayerId) && !bPicSkipped)
@@ -276,6 +292,10 @@ uint32_t DecApp::decode()
     {
       m_cDecLib.checkSeiInPictureUnit();
       m_cDecLib.resetPictureSeiNalus();
+#if JVET_S0155_EOS_NALU_CHECK
+      // reset the EOS present status for the next PU check
+      isEosPresentInPu = false;
+#endif
     }
     if (bNewPicture || !bitstreamFile || nalu.m_nalUnitType == NAL_UNIT_EOS)
     {
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index fcd9b8e242f52c2903ceac5abda413e09aceaa8f..1642c2b199835112615992adfc2e76c673c1eb63 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -67,6 +67,9 @@
 
 #define JVET_S0065_SPS_INFERENCE_RULE                     1 // JVET_S0065_PROPOSAL1: Inference rule for sps_virtual_boundaries_present_flag
 
+#define JVET_S0155_EOS_NALU_CHECK                         1 // JVET-S0155: Constraints on EOS NAL units
+
+
 //########### place macros to be be kept below this line ###############
 #define JVET_S0257_DUMP_360SEI_MESSAGE                    1 // Software support of 360 SEI messages
 
diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index 3fe5ead148584045af796b1f0b18d05445e2bd39..0ee14c9ff1154790e5ca5009b8f8174e4fe1603c 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -455,6 +455,9 @@ DecLib::DecLib()
 {
 #if ENABLE_SIMD_OPT_BUFFER
   g_pelBufOP.initPelBufOpsX86();
+#endif
+#if JVET_S0155_EOS_NALU_CHECK
+  memset(m_prevEOS, false, sizeof(m_prevEOS));
 #endif
   memset(m_accessUnitEos, false, sizeof(m_accessUnitEos));
   for (int i = 0; i < MAX_VPS_LAYERS; i++)
@@ -893,6 +896,19 @@ void DecLib::xCreateUnavailablePicture(int iUnavailablePoc, bool longTermFlag, c
     m_pocRandomAccess = iUnavailablePoc;
   }
 }
+#if JVET_S0155_EOS_NALU_CHECK
+void DecLib::checkPicTypeAfterEos()
+{
+  int layerId = m_pcPic->slices[0]->getNalUnitLayerId();
+  if (m_prevEOS[layerId])
+  {
+    bool isIrapOrGdrPu = !m_pcPic->cs->pps->getMixedNaluTypesInPicFlag() && ( m_pcPic->slices[0]->isIRAP() || m_pcPic->slices[0]->getNalUnitType() == NAL_UNIT_CODED_SLICE_GDR );
+    CHECK(!isIrapOrGdrPu, "when present, the next PU of a particular layer after an EOS NAL unit that belongs to the same layer shall be an IRAP or GDR PU");
+
+    m_prevEOS[layerId] = false;
+  }
+}
+#endif
 
 void DecLib::checkLayerIdIncludedInCvss()
 {
@@ -923,6 +939,28 @@ void DecLib::checkLayerIdIncludedInCvss()
       }
       CHECK(!layerIdFind, "each picture in an AU in a CVS shall have nuh_layer_id equal to the nuh_layer_id of one of the pictures present in the first AU of the CVS");
     }
+
+
+#if JVET_S0155_EOS_NALU_CHECK
+    // check whether the layerID of EOS_NUT is included in the layerIDs of the first AU
+    for (int i = 0; i < getVPS()->getMaxLayers(); i++)
+    {
+      int eosLayerId = getVPS()->getLayerId(i);
+      if (m_accessUnitEos[eosLayerId])
+      {
+        bool eosLayerIdFind;
+        for (auto picFirst = m_firstAccessUnitPicInfo.begin(); picFirst != m_firstAccessUnitPicInfo.end(); picFirst++)
+        {
+          eosLayerIdFind = eosLayerId == picFirst->m_nuhLayerId ? true : false;
+          if (eosLayerIdFind)
+          {
+            break;
+          }
+        }
+        CHECK(!eosLayerIdFind, "When nal_unit_type is equal to EOS_NUT, nuh_layer_id shall be equal to one of the nuh_layer_id values of the layers present in the CVS");
+      }
+    }
+#endif
   }
 
   // update the value of m_isFirstAuInCvs for the next AU according to NAL_UNIT_EOS in each layer
@@ -2181,6 +2219,9 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl
     m_pcPic->setDecodingOrderNumber(m_decodingOrderCounter);
     m_decodingOrderCounter++;
     m_pcPic->setPictureType(nalu.m_nalUnitType);
+#if JVET_S0155_EOS_NALU_CHECK
+    checkPicTypeAfterEos();
+#endif
     // store sub-picture numbers, sizes, and locations with a picture
     pcSlice->getPic()->numSubpics = sps->getNumSubPics();
     pcSlice->getPic()->subpicWidthInCTUs.clear();
@@ -2735,6 +2776,9 @@ bool DecLib::decode(InputNALUnit& nalu, int& iSkipFrame, int& iPOCLastDisplay, i
       m_prevSliceSkipped = false;
       m_skippedPOC = 0;
       m_accessUnitEos[nalu.m_nuhLayerId] = true;
+#if JVET_S0155_EOS_NALU_CHECK
+      m_prevEOS[nalu.m_nuhLayerId] = true;
+#endif
       return false;
 
     case NAL_UNIT_ACCESS_UNIT_DELIMITER:
diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h
index 6202c7de30e74073ef28cceb00e083d1e969552b..7279c30f0fec70ed027b39e908db49a71e14e9ce 100644
--- a/source/Lib/DecoderLib/DecLib.h
+++ b/source/Lib/DecoderLib/DecLib.h
@@ -85,6 +85,9 @@ private:
   int                     m_prevIRAPSubpicDecOrderNo[MAX_VPS_LAYERS][MAX_NUM_SUB_PICS];
   int                     m_pocRandomAccess;   ///< POC number of the random access point (the first IDR or CRA picture)
   int                     m_lastRasPoc;
+#if JVET_S0155_EOS_NALU_CHECK
+  bool                    m_prevEOS[MAX_VPS_LAYERS];
+#endif
 
   PicList                 m_cListPic;         //  Dynamic buffer
   ParameterSetManager     m_parameterSetManager;  // storage for parameter sets
@@ -217,6 +220,9 @@ public:
   void  finishPictureLight(int& poc, PicList*& rpcListPic );
   void  checkNoOutputPriorPics (PicList* rpcListPic);
   void  checkNalUnitConstraints( uint32_t naluType );
+#if JVET_S0155_EOS_NALU_CHECK
+  void  checkPicTypeAfterEos();
+#endif
   void  updateAssociatedIRAP();
   void  updatePrevGDRInSameLayer();
   void  updatePrevIRAPAndGDRSubpic();