diff --git a/cfg/encoder_intra_ecm.cfg b/cfg/encoder_intra_ecm.cfg
index 02726537c8685d5bc7600656614dd59655439f26..6366f730c6c827f5d4b7c0e89a8be548a4c508dd 100644
--- a/cfg/encoder_intra_ecm.cfg
+++ b/cfg/encoder_intra_ecm.cfg
@@ -79,7 +79,9 @@ MTS                          : 1
 MTSIntraMaxCand              : 4
 MTSInterMaxCand              : 4
 SBT                          : 1
-LFNST                        : 1
+IntraLFNSTISlice             : 1
+IntraLFNSTPBSlice            : 1
+InterLFNST                   : 1
 ISP                          : 1
 Affine                       : 1
 SbTMVP                       : 1
diff --git a/cfg/encoder_lowdelay_P_ecm.cfg b/cfg/encoder_lowdelay_P_ecm.cfg
index 86840958ab3ef2a8c1162d546468ff441c556851..81632b2112a0f8e784db7d6b939cb0928baf007a 100644
--- a/cfg/encoder_lowdelay_P_ecm.cfg
+++ b/cfg/encoder_lowdelay_P_ecm.cfg
@@ -104,6 +104,9 @@ MTS                          : 3
 MTSIntraMaxCand              : 3
 MTSInterMaxCand              : 4
 SBT                          : 1
+IntraLFNSTISlice             : 1
+IntraLFNSTPBSlice            : 0
+InterLFNST                   : 1
 ISP                          : 1
 Affine                       : 1
 SbTMVP                       : 1
@@ -140,6 +143,8 @@ ISPFast                      : 0
 FastMrg                      : 1
 AMaxBT                       : 1
 FastMIP                      : 0
+FastLFNST                    : 0
+FastInterLFNST               : 1
 MTTSkipping                  : 1      # MTTSkipping: 0: disable, 1:enable
 
 # Encoder optimization tools
diff --git a/cfg/encoder_lowdelay_ecm.cfg b/cfg/encoder_lowdelay_ecm.cfg
index 7ad59713347a937654a228ec2d95e9b75f996470..f1def45954326bbf91fe3ffedeed7e096138c1d3 100644
--- a/cfg/encoder_lowdelay_ecm.cfg
+++ b/cfg/encoder_lowdelay_ecm.cfg
@@ -104,6 +104,9 @@ MTS                          : 3
 MTSIntraMaxCand              : 3
 MTSInterMaxCand              : 4
 SBT                          : 1
+IntraLFNSTISlice             : 1
+IntraLFNSTPBSlice            : 0
+InterLFNST                   : 1
 ISP                          : 1
 MMVD                         : 1
 Affine                       : 1
@@ -144,6 +147,8 @@ ISPFast                      : 0
 FastMrg                      : 1
 AMaxBT                       : 1
 FastMIP                      : 0
+FastLFNST                    : 0
+FastInterLFNST               : 1
 MTTSkipping                  : 1      # MTTSkipping: 0: disable, 1:enable
 
 # Encoder optimization tools
diff --git a/cfg/encoder_randomaccess_ecm.cfg b/cfg/encoder_randomaccess_ecm.cfg
index 203e92d3941810e27a3eb1283ce392f357524eb3..9df53758e22bc5283cc384b41fbcb96da08c4533 100644
--- a/cfg/encoder_randomaccess_ecm.cfg
+++ b/cfg/encoder_randomaccess_ecm.cfg
@@ -131,7 +131,9 @@ MTS                          : 3
 MTSIntraMaxCand              : 4
 MTSInterMaxCand              : 4
 SBT                          : 1
-LFNST                        : 1
+IntraLFNSTISlice             : 1
+IntraLFNSTPBSlice            : 1
+InterLFNST                   : 1
 ISP                          : 1
 MMVD                         : 1
 Affine                       : 1
@@ -174,6 +176,7 @@ FastMrg                      : 1
 AMaxBT                       : 1
 FastMIP                      : 0
 FastLFNST                    : 0
+FastInterLFNST               : 0
 ChromaTS                     : 1
 MTTSkipping                  : 1      # MTTSkipping: 0: disable, 1:enable
 
diff --git a/cfg/encoder_randomaccess_gop16_ecm.cfg b/cfg/encoder_randomaccess_gop16_ecm.cfg
index 18b7c9a00e635ddb0d18b1301eb9f0d260b40274..d7d98040d7d5d873db49128120fb7f83a8183b61 100644
--- a/cfg/encoder_randomaccess_gop16_ecm.cfg
+++ b/cfg/encoder_randomaccess_gop16_ecm.cfg
@@ -115,7 +115,9 @@ MTS                          : 1
 MTSIntraMaxCand              : 4
 MTSInterMaxCand              : 4
 SBT                          : 1
-LFNST                        : 1
+IntraLFNSTISlice             : 1
+IntraLFNSTPBSlice            : 1
+InterLFNST                   : 1
 ISP                          : 1
 MMVD                         : 1
 Affine                       : 1
@@ -158,6 +160,7 @@ FastMrg                      : 1
 AMaxBT                       : 1
 FastMIP                      : 0
 FastLFNST                    : 0
+FastInterLFNST               : 0
 ChromaTS                     : 1
 MTTSkipping                  : 1      # MTTSkipping: 0: disable, 1:enable
 
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 1e24e4cdb824a6ce6bc2b49fc0f6993ee8ca6001..4d5d237f3493d8612b9f8d10eee6acc775cb534c 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -493,7 +493,13 @@ void EncApp::xInitLibCfg()
     CHECK(m_noMipConstraintFlag && m_MIP, "MIP shall be deactivated when m_noMipConstraintFlag is equal to 1");
 
     m_cEncLib.setNoLfnstConstraintFlag(m_noLfnstConstraintFlag);
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    bool spsLfnstEnabled = ( m_intraLFNSTISlice || m_intraLFNSTPBSlice );
+    spsLfnstEnabled |= m_interLFNST;
+    CHECK( m_noLfnstConstraintFlag && spsLfnstEnabled, "LFNST shall be deactivated when m_noLfnstConstraintFlag is equal to 1" );
+#else
     CHECK(m_noLfnstConstraintFlag && m_LFNST, "LFNST shall be deactivated when m_noLfnstConstraintFlag is equal to 1");
+#endif
 
     m_cEncLib.setNoMmvdConstraintFlag(m_noMmvdConstraintFlag);
     CHECK(m_noMmvdConstraintFlag && m_MMVD, "MMVD shall be deactivated when m_noMmvdConstraintFlag is equal to 1");
@@ -804,8 +810,17 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setLog2SignPredArea                                  (m_log2SignPredArea);
 #endif
 #endif
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  m_cEncLib.setIntraLFNSTISlice                                  ( m_intraLFNSTISlice );
+  m_cEncLib.setIntraLFNSTPBSlice                                 ( m_intraLFNSTPBSlice );
+  m_cEncLib.setInterLFNST                                        ( m_interLFNST );
+#else
   m_cEncLib.setLFNST                                             ( m_LFNST );
+#endif
   m_cEncLib.setUseFastLFNST                                      ( m_useFastLFNST );
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  m_cEncLib.setUseFastInterLFNST                                 ( m_useFastInterLFNST );
+#endif
   m_cEncLib.setSbTmvpEnabledFlag(m_sbTmvpEnableFlag);
   m_cEncLib.setAffine                                            ( m_Affine );
   m_cEncLib.setAffineType                                        ( m_AffineType );
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index d8032107fd686efe39aca62eefc471f6a3772748..f3f85bb99469dc1737a21c6a6f58f593ab5feb89 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1028,8 +1028,17 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("TTFastSkipThr",                                   m_ttFastSkipThr,                                  1.075, "Threshold value of fast skip method for TT split partition")
 #endif
   ("DualITree",                                       m_dualTree,                                       false, "Use separate QTBT trees for intra slice luma and chroma channel types")
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  ( "IntraLFNSTISlice",                               m_intraLFNSTISlice,                               false, "Enable intra-LFNST for I-Slice (0:off, 1:on)  [default: off]" )
+  ( "IntraLFNSTPBSlice",                              m_intraLFNSTPBSlice,                              false, "Enable intra-LFNST for P/B-Slice (0:off, 1:on)  [default: off]" )
+  ( "InterLFNST",                                     m_interLFNST,                                     false, "Enable inter-LFNST/NSPT (0:off, 1:on)  [default: off]" )
+#else
   ( "LFNST",                                          m_LFNST,                                          false, "Enable LFNST (0:off, 1:on)  [default: off]" )
+#endif
   ( "FastLFNST",                                      m_useFastLFNST,                                   false, "Fast methods for LFNST" )
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  ( "FastInterLFNST",                                 m_useFastInterLFNST,                              false, "Fast methods for inter-LFNST/NSPT" )
+#endif
   ("SbTMVP",                                          m_sbTmvpEnableFlag,                               false, "Enable Subblock Temporal Motion Vector Prediction (0: off, 1: on) [default: off]")
   ("MMVD",                                            m_MMVD,                                            true, "Enable Merge mode with Motion Vector Difference (0:off, 1:on)  [default: 1]")
   ("Affine",                                          m_Affine,                                         false, "Enable affine prediction (0:off, 1:on)  [default: off]")
@@ -5572,7 +5581,13 @@ void EncAppCfg::xPrintParameter()
   {
     msg( VERBOSE, "\nTOOL CFG: " );
     msg( VERBOSE, "GOP:%d ", m_iGOPSize );
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    msg( VERBOSE, "IntraLFNSTISlice:%d ", m_intraLFNSTISlice );
+    msg( VERBOSE, "IntraLFNSTPBSlice:%d ", m_intraLFNSTPBSlice );
+    msg( VERBOSE, "InterLFNST:%d ", m_interLFNST );
+#else
     msg( VERBOSE, "LFNST:%d ", m_LFNST );
+#endif
     msg( VERBOSE, "MMVD:%d ", m_MMVD);
     msg( VERBOSE, "Affine:%d ", m_Affine );
     if ( m_Affine )
@@ -5730,7 +5745,16 @@ void EncAppCfg::xPrintParameter()
   if( m_ImvMode ) msg( VERBOSE, "IMV4PelFast:%d ", m_Imv4PelFast );
   if( m_MTS ) msg( VERBOSE, "MTSMaxCand: %1d(intra) %1d(inter) ", m_MTSIntraMaxCand, m_MTSInterMaxCand );
   if( m_ISP ) msg( VERBOSE, "ISPFast:%d ", m_useFastISP );
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  if( m_intraLFNSTISlice || m_intraLFNSTPBSlice ) msg( VERBOSE, "FastLFNST:%d ", m_useFastLFNST );
+#else
   if( m_LFNST ) msg( VERBOSE, "FastLFNST:%d ", m_useFastLFNST );
+#endif
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool lfnstEnabled = ( m_intraLFNSTISlice || m_intraLFNSTPBSlice );
+  lfnstEnabled |= m_interLFNST;
+  if( lfnstEnabled ) msg( VERBOSE, "FastInterLFNST:%d ", m_useFastInterLFNST );
+#endif
   msg( VERBOSE, "AMaxBT:%d ", m_useAMaxBT );
   msg( VERBOSE, "E0023FastEnc:%d ", m_e0023FastEnc );
   msg( VERBOSE, "ContentBasedFastQtbt:%d ", m_contentBasedFastQtbt );
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index dc8a06a036134f157de7739e160dc8c15c53d0e1..e7bd2baad728c284dfa8cf8012c6270372ce11e2 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -392,8 +392,17 @@ protected:
   double    m_ttFastSkipThr;
 #endif
   bool      m_dualTree;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool      m_intraLFNSTISlice;
+  bool      m_intraLFNSTPBSlice;
+  bool      m_interLFNST;
+#else
   bool      m_LFNST;
+#endif
   bool      m_useFastLFNST;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool      m_useFastInterLFNST;
+#endif
   bool      m_sbTmvpEnableFlag;
   bool      m_Affine;
   bool      m_AffineType;
diff --git a/source/Lib/CommonLib/DepQuant.cpp b/source/Lib/CommonLib/DepQuant.cpp
index c5024cb6054218fec20830176e01e8f5be49636c..7ae5a97687b3c6d172b0bacb7184064d3312b0fe 100644
--- a/source/Lib/CommonLib/DepQuant.cpp
+++ b/source/Lib/CommonLib/DepQuant.cpp
@@ -2684,7 +2684,13 @@ const CtxSet &ctxSetGt4 = isLfnst ? Ctx::GtxFlagL[6 + chType] : Ctx::GtxFlag[6 +
     {
 #if JVET_W0119_LFNST_EXTENSION
 #if JVET_AC0130_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                    ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+      bool allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) );
+#else
       bool allowNSPT = CU::isNSPTAllowed(tu, compID, width, height, CU::isIntra(*(tu.cu)));
+#endif
 
       if (allowNSPT)
       {
@@ -2699,7 +2705,13 @@ const CtxSet &ctxSetGt4 = isLfnst ? Ctx::GtxFlagL[6 + chType] : Ctx::GtxFlag[6 +
 #endif
 #else
 #if JVET_AC0130_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                    ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+      bool allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) );
+#else
       bool allowNSPT = CU::isNSPTAllowed(tu, compID, width, height, CU::isIntra(*(tu.cu)));
+#endif
 
       if (allowNSPT)
       {
diff --git a/source/Lib/CommonLib/Quant.cpp b/source/Lib/CommonLib/Quant.cpp
index a6dd4a7a7eb83c4e5d175707978a992cd90476fc..b9fdcf51446d905d871639dc4456b393d209e846 100644
--- a/source/Lib/CommonLib/Quant.cpp
+++ b/source/Lib/CommonLib/Quant.cpp
@@ -1010,7 +1010,13 @@ void Quant::quant(TransformUnit &tu, const ComponentID &compID, const CCoeffBuf
     const uint32_t lfnstIdx = tu.cu->lfnstIdx;
 #if JVET_W0119_LFNST_EXTENSION
 #if JVET_AC0130_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                  ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+    bool allowNSPT = CU::isNSPTAllowed( tu, compID, uiWidth, uiHeight, spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) );
+#else
     bool allowNSPT = CU::isNSPTAllowed( tu, compID, uiWidth, uiHeight, CU::isIntra( *( tu.cu ) ) );
+#endif
 
     const int maxNumberOfCoeffs = lfnstIdx > 0 ? ( allowNSPT ? PU::getNSPTMatrixDim( uiWidth, uiHeight ) : PU::getLFNSTMatrixDim( uiWidth, uiHeight ) ) : piQCoef.area();
 #else
@@ -1018,7 +1024,13 @@ void Quant::quant(TransformUnit &tu, const ComponentID &compID, const CCoeffBuf
 #endif
 #else
 #if JVET_AC0130_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                  ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+    bool allowNSPT = CU::isNSPTAllowed( tu, compID, uiWidth, uiHeight, spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) );
+#else
     bool allowNSPT = CU::isNSPTAllowed( tu, compID, uiWidth, uiHeight, CU::isIntra( *( tu.cu ) ) );
+#endif
 
     const int maxNumberOfCoeffs = lfnstIdx > 0 ? ( allowNSPT ? PU::getNSPTMatrixDim( uiWidth, uiHeight ) : ( ( ( uiWidth == 4 && uiHeight == 4 ) || ( uiWidth == 8 && uiHeight == 8 ) ) ? 8 : 16 ) ) : piQCoef.area();
 #else
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index 9b02bafe3dc73e111149c58e17994d7861f29a2e..2f11cb39fa5ba669ef55772c455a6839efd56e6c 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -3897,7 +3897,13 @@ SPS::SPS()
 , m_verCollocatedChromaFlag   ( false )
 , m_IntraMTS                  ( false )
 , m_InterMTS                  ( false )
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+, m_intraLFNSTISlice          ( false )
+, m_intraLFNSTPBSlice         ( false )
+, m_interLFNST                ( false )
+#else
 , m_LFNST                     ( false )
+#endif
 , m_Affine                    ( false )
 , m_AffineType                ( false )
 #if JVET_AF0163_TM_SUBBLOCK_REFINEMENT
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index b36f05e40bce68b13088e924546a26bff8dfb92a..39633a31ff1bb34e4d8459be9bdf4bc81d725306 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -1774,7 +1774,13 @@ private:
   bool              m_MTS;
   bool              m_IntraMTS;                   // 18
   bool              m_InterMTS;                   // 19
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool              m_intraLFNSTISlice;
+  bool              m_intraLFNSTPBSlice;
+  bool              m_interLFNST;
+#else
   bool              m_LFNST;
+#endif
   bool              m_SMVD;
   bool              m_Affine;
   bool              m_AffineType;
@@ -2459,8 +2465,17 @@ void                    setCCALFEnabledFlag( bool b )
   bool      getUseIntraMTS        ()                                      const     { return m_IntraMTS; }
   void      setUseInterMTS        ( bool b )                                        { m_InterMTS = b; }
   bool      getUseInterMTS        ()                                      const     { return m_InterMTS; }
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  void      setUseIntraLFNSTISlice  ( bool b )                                      { m_intraLFNSTISlice = b; }
+  bool      getUseIntraLFNSTISlice  ()                                    const     { return m_intraLFNSTISlice; }
+  void      setUseIntraLFNSTPBSlice ( bool b )                                      { m_intraLFNSTPBSlice = b; }
+  bool      getUseIntraLFNSTPBSlice ()                                    const     { return m_intraLFNSTPBSlice; }
+  void      setUseInterLFNST      ( bool b )                                        { m_interLFNST = b; }
+  bool      getUseInterLFNST      ()                                      const     { return m_interLFNST; }
+#else
   void      setUseLFNST           ( bool b )                                        { m_LFNST = b; }
   bool      getUseLFNST           ()                                      const     { return m_LFNST; }
+#endif
   void      setUseSMVD(bool b)                                                      { m_SMVD = b; }
   bool      getUseSMVD()                                                  const     { return m_SMVD; }
   void      setUseBcw             ( bool b )                                        { m_bcw = b; }
diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp
index 4c0b9d24ab785eb8122608a378560cb99e8288ce..1e48b2621a9eca7654c56db0917726195daeb3e2 100644
--- a/source/Lib/CommonLib/TrQuant.cpp
+++ b/source/Lib/CommonLib/TrQuant.cpp
@@ -477,7 +477,13 @@ void TrQuant::xInvLfnst( const TransformUnit &tu, const ComponentID compID )
 #endif
   {
 #if JVET_AC0130_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                  ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+    bool allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) );
+#else
     bool allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, CU::isIntra( *( tu.cu ) ) );
+#endif
     if( allowNSPT )
     {
       return;
@@ -770,7 +776,13 @@ void TrQuant::xFwdLfnst( const TransformUnit &tu, const ComponentID compID, cons
 #endif
   {
 #if JVET_AC0130_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                  ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+    bool allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) );
+#else
     bool allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, CU::isIntra( *( tu.cu ) ) );
+#endif
     if( allowNSPT )
     {
       return;
@@ -1057,7 +1069,13 @@ void TrQuant::invTransformNxN( TransformUnit &tu, const ComponentID &compID, Pel
 
   DTRACE_COEFF_BUF(D_TCOEFF, tempCoeff, tu, tu.cu->predMode, compID);
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+  if( ( spsIntraLfnstEnabled && CU::isIntra( *tu.cu ) ) || ( tu.cs->sps->getUseInterLFNST() && CU::isInter( *tu.cu ) ) )
+#else
   if (tu.cs->sps->getUseLFNST())
+#endif
   {
     xInvLfnst(tu, compID);
   }
@@ -1393,8 +1411,14 @@ void TrQuant::xT( const TransformUnit &tu, const ComponentID &compID, const CPel
 #endif
 
 #if JVET_AC0130_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+  bool allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) );
+#else
   const bool allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, CU::isIntra( *(tu.cu) ) );
 #endif
+#endif
 
 #if EXTENDED_LFNST
   if( tu.cs->sps->getUseLFNST() && tu.cu->lfnstIdx && width >= 4 && height >= 4)
@@ -1405,10 +1429,18 @@ void TrQuant::xT( const TransformUnit &tu, const ComponentID &compID, const CPel
     skipHeight = height - lfnst_threshold;
   }
 #else
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+#if JVET_AC0130_NSPT
+  if( ( ( spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) ) || ( tu.cs->sps->getUseInterLFNST() && CU::isInter( *( tu.cu ) ) ) ) && tu.cu->lfnstIdx && !allowNSPT )
+#else
+  if( ( ( spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) ) || ( tu.cs->sps->getUseInterLFNST() && CU::isInter( *( tu.cu ) ) ) ) && tu.cu->lfnstIdx )
+#endif
+#else
 #if JVET_AC0130_NSPT
   if( tu.cs->sps->getUseLFNST() && tu.cu->lfnstIdx && !allowNSPT )
 #else
   if( tu.cs->sps->getUseLFNST() && tu.cu->lfnstIdx )
+#endif
 #endif
   {
     if( ( width == 4 && height > 16 ) || ( width > 16 && height == 4 ) )
@@ -1516,8 +1548,14 @@ void TrQuant::xIT( const TransformUnit &tu, const ComponentID &compID, const CCo
 #endif
 
 #if JVET_AC0130_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+  bool allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) );
+#else
   const bool allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, CU::isIntra( *(tu.cu) ) );
 #endif
+#endif
 
 #if EXTENDED_LFNST
   if (tu.cs->sps->getUseLFNST() && tu.cu->lfnstIdx && width >= 4 && height >= 4)
@@ -1528,10 +1566,18 @@ void TrQuant::xIT( const TransformUnit &tu, const ComponentID &compID, const CCo
     skipHeight = height - lfnst_threshold;
   }
 #else
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+#if JVET_AC0130_NSPT
+  if( ( ( spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) ) || ( tu.cs->sps->getUseInterLFNST() && CU::isInter( *( tu.cu ) ) ) ) && tu.cu->lfnstIdx && !allowNSPT )
+#else
+  if( ( ( spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) ) || ( tu.cs->sps->getUseInterLFNST() && CU::isInter( *( tu.cu ) ) ) ) && tu.cu->lfnstIdx )
+#endif
+#else
 #if JVET_AC0130_NSPT
   if( tu.cs->sps->getUseLFNST() && tu.cu->lfnstIdx && !allowNSPT )
 #else
   if( tu.cs->sps->getUseLFNST() && tu.cu->lfnstIdx )
+#endif
 #endif
   {
     if( ( width == 4 && height > 16 ) || ( width > 16 && height == 4 ) )
@@ -2130,14 +2176,26 @@ void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const
       xT(tu, compID, resiBuf, tempCoeff, uiWidth, uiHeight);
     }
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                  ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+    if( ( spsIntraLfnstEnabled && CU::isIntra( *tu.cu ) ) || ( sps.getUseInterLFNST() && CU::isInter( *tu.cu ) ) )
+#else
     if (sps.getUseLFNST())
+#endif
     {
       xFwdLfnst(tu, compID);
     }
 #endif
   }
 #if !JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+  if( ( spsIntraLfnstEnabled && CU::isIntra( *tu.cu ) ) || ( sps.getUseInterLFNST() && CU::isInter( *tu.cu ) ) )
+#else
   if (sps.getUseLFNST())
+#endif
   {
     xFwdLfnst(tu, compID, loadTr);
   }
@@ -2388,7 +2446,13 @@ void TrQuant::predCoeffSigns(TransformUnit &tu, const ComponentID compID, const
   int log2Width = floorLog2(uiWidth);
   int log2Height = floorLog2(uiHeight);
   int actualTrIdx = 0, actualLfnstIdx = 0;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+  bool lfnstEnabled = ( ( ( spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) ) || ( tu.cu->cs->sps->getUseInterLFNST() && CU::isInter( *( tu.cu ) ) ) ) && tu.checkLFNSTApplied( residCompID ) );
+#else
   bool lfnstEnabled = tu.checkLFNSTApplied(residCompID);
+#endif
   if (lfnstEnabled)
   {
     actualLfnstIdx = getLfnstIdx(tu, residCompID);
@@ -2785,7 +2849,13 @@ int TrQuant::getLfnstIdx(const TransformUnit &tu, ComponentID compID)
   CHECK((lfnstIdx != 1) && (lfnstIdx != 2), "invalid lfnst idx");
 #endif
 #if JVET_AC0130_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+  bool allowNSPT = CU::isNSPTAllowed( tu, compID, area.width, area.height, spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) );
+#else
   bool allowNSPT = CU::isNSPTAllowed( tu, compID, area.width, area.height, CU::isIntra( *( tu.cu ) ) );
+#endif
   intraMode = allowNSPT ? PU::getNSPTIntraMode( PU::getWideAngle( tu, intraMode, compID ) ) : getLFNSTIntraMode( PU::getWideAngle( tu, intraMode, compID ) );
 #else
   intraMode = getLFNSTIntraMode(PU::getWideAngle(tu, intraMode, compID));
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 1b0ab966ea3dfdc2e236b4c9dde77996da41bd0f..4e39367b5b4fca2d8ea6128817c64278379ebaea 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -402,6 +402,7 @@
 #define JVET_AG0061_INTER_LFNST_NSPT                      1 // JVET-AG0061: 3.3 Utilizing LFNST/NSPT for inter coding
 #define JVET_AG0100_TRANSFORM_COEFFICIENT_CODING          1 // JVET_AG0100: 3.2b Transform coefficient coding
 #define JVET_AG0143_INTER_INTRA                           1 // JVET_AG0143: 3.1c CABAC inter/intra model switch
+#define JVET_AH0103_LOW_DELAY_LFNST_NSPT                  1 // JVET_AH0103: Low-delay configurations for LFNST/NSPT
 
 // Entropy Coding
 #define EC_HIGH_PRECISION                                 1 // CABAC high precision
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 2b943a60ab2bb972a63e93b53ba470597dd95489..8823129e63632b98158936ceb5e4234690e8d8a5 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -29700,7 +29700,11 @@ bool CU::isNSPTAllowed( const TransformUnit &tu, const ComponentID compID, int w
 {
   bool allowNSPT = isIntra;
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  if( tu.cs->sps->getUseInterLFNST() && CU::isInter( *tu.cu ) )
+#else
   if (CU::isInter(*tu.cu))
+#endif
   {
     allowNSPT = true;
   }
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index 72ab4d649d397e1b1baa0e749e6ab4c14088554c..0eb3543011dbe31271930946705a4eae4bc3e485 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -8519,7 +8519,13 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID, CUCtx&
 #if JVET_AC0130_NSPT
     uint32_t  width = tu.blocks[ compID ].width;
     uint32_t height = tu.blocks[ compID ].height;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                  ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+    bool allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) );
+#else
     bool  allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, CU::isIntra( *( tu.cu ) ) );
+#endif
 
 #if JVET_W0119_LFNST_EXTENSION
     const int maxLfnstPos = ( allowNSPT ? PU::getNSPTMatrixDim( width, height ) : PU::getLFNSTMatrixDim( width, height ) ) - 1;
@@ -8782,13 +8788,25 @@ void CABACReader::residual_lfnst_mode( CodingUnit& cu,  CUCtx& cuCtx  )
   int chIdx = CS::isDualITree(*cu.cs) && cu.chType == CHANNEL_TYPE_CHROMA ? 1 : 0;
 #else
   int chIdx = cu.isSepTree() && cu.chType == CHANNEL_TYPE_CHROMA ? 1 : 0;
+#endif
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsIntraLfnstEnabled = ( ( cu.slice->getSliceType() == I_SLICE && cu.cs->sps->getUseIntraLFNSTISlice() ) ||
+                                ( cu.slice->getSliceType() != I_SLICE && cu.cs->sps->getUseIntraLFNSTPBSlice() ) );
 #endif
   if ((cu.ispMode && !CU::canUseLfnstWithISP(cu, cu.chType))
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+#if JVET_V0130_INTRA_TMP
+    || ( spsIntraLfnstEnabled && CU::isIntra( cu ) && ( ( cu.mipFlag && !allowLfnstWithMip( cu.firstPU->lumaSize() ) ) || ( cu.tmpFlag && !allowLfnstWithTmp() ) ) )
+#else
+    || ( spsIntraLfnstEnabled && CU::isIntra( cu ) && cu.mipFlag && !allowLfnstWithMip( cu.firstPU->lumaSize() ) )
+#endif
+#else
 #if JVET_V0130_INTRA_TMP
     || (cu.cs->sps->getUseLFNST() && CU::isIntra(cu) && ((cu.mipFlag && !allowLfnstWithMip(cu.firstPU->lumaSize())) || (cu.tmpFlag && !allowLfnstWithTmp())))
 #else
     || (cu.cs->sps->getUseLFNST() && CU::isIntra(cu) && cu.mipFlag && !allowLfnstWithMip(cu.firstPU->lumaSize()))
 #endif
+#endif
 #if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
     || (CS::isDualITree(*cu.cs) && cu.chType == CHANNEL_TYPE_CHROMA && std::min(cu.blocks[1].width, cu.blocks[1].height) < 4)
 #else
@@ -8811,9 +8829,17 @@ void CABACReader::residual_lfnst_mode( CodingUnit& cu,  CUCtx& cuCtx  )
 #endif
 
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  if( ( spsIntraLfnstEnabled && CU::isIntra( cu ) ) || ( cu.cs->sps->getUseInterLFNST() && CU::isInter( cu ) ) )
+#else
   if (cu.cs->sps->getUseLFNST() && (CU::isIntra(cu) || CU::isInter(cu)))
+#endif
+#else
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  if( spsIntraLfnstEnabled && CU::isIntra( cu ) )
 #else
   if (cu.cs->sps->getUseLFNST() && CU::isIntra(cu))
+#endif
 #endif
   {
 #if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index 882575d6aae92ac71ad3b1a7269d9d8bbaee71aa..d099894c61ace4fa7c2052019d02d21887300f3a 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -2085,8 +2085,14 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
     }
 #endif
   }
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  READ_FLAG( uiCode, "sps_intra_lfnst_intra_slice_enabled_flag" );               pcSPS->setUseIntraLFNSTISlice( uiCode != 0 );
+  READ_FLAG( uiCode, "sps_intra_lfnst_inter_slice_enabled_flag" );               pcSPS->setUseIntraLFNSTPBSlice( uiCode != 0 );
+  READ_FLAG( uiCode, "sps_inter_lfnst_enabled_flag" );            pcSPS->setUseInterLFNST( uiCode != 0 );
+#else
   READ_FLAG(uiCode, "sps_lfnst_enabled_flag");                    pcSPS->setUseLFNST(uiCode != 0);
 #endif
+#endif
 
 #if JVET_S0052_RM_SEPARATE_COLOUR_PLANE
   if (pcSPS->getChromaFormatIdc() != CHROMA_400)
@@ -2916,7 +2922,13 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
   }
 #endif
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsLfnstEnabled = ( pcSPS->getUseIntraLFNSTISlice() || pcSPS->getUseIntraLFNSTPBSlice() );
+  spsLfnstEnabled |= pcSPS->getUseInterLFNST();
+  if( spsLfnstEnabled && pcSPS->getScalingListFlag() )
+#else
   if (pcSPS->getUseLFNST() && pcSPS->getScalingListFlag())
+#endif
   {
     READ_FLAG(uiCode, "scaling_matrix_for_lfnst_disabled_flag"); pcSPS->setDisableScalingMatrixForLfnstBlks(uiCode ? true : false);
   }
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index 7836398289583cd5b10b10f12f5d953b3916f87c..bbbef76b7823bd0f89c1fec41d0e8d6cde6bf6bb 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -8302,7 +8302,13 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID,
 #if JVET_AC0130_NSPT
       uint32_t  width = tu.blocks[compID].width;
       uint32_t height = tu.blocks[compID].height;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      bool spsIntraLfnstEnabled = ( ( tu.cu->slice->getSliceType() == I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTISlice() ) ||
+                                    ( tu.cu->slice->getSliceType() != I_SLICE && tu.cu->cs->sps->getUseIntraLFNSTPBSlice() ) );
+      bool allowNSPT = CU::isNSPTAllowed( tu, compID, width, height, spsIntraLfnstEnabled && CU::isIntra( *( tu.cu ) ) );
+#else
       bool  allowNSPT = CU::isNSPTAllowed(tu, compID, width, height, CU::isIntra(*(tu.cu)));
+#endif
 
 #if JVET_W0119_LFNST_EXTENSION
       const int maxLfnstPos = (allowNSPT ? PU::getNSPTMatrixDim(width, height) : PU::getLFNSTMatrixDim(width, height)) - 1;
@@ -8578,13 +8584,25 @@ void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx )
   int chIdx = CS::isDualITree(*cu.cs) && cu.chType == CHANNEL_TYPE_CHROMA ? 1 : 0;
 #else
   int chIdx = cu.isSepTree() && cu.chType == CHANNEL_TYPE_CHROMA ? 1 : 0;
+#endif
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsIntraLfnstEnabled = ( ( cu.slice->getSliceType() == I_SLICE && cu.cs->sps->getUseIntraLFNSTISlice() ) ||
+                                ( cu.slice->getSliceType() != I_SLICE && cu.cs->sps->getUseIntraLFNSTPBSlice() ) );
 #endif
   if( ( cu.ispMode && !CU::canUseLfnstWithISP( cu, cu.chType ) ) ||
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+#if JVET_V0130_INTRA_TMP
+    ( spsIntraLfnstEnabled && CU::isIntra( cu ) && ( ( cu.mipFlag && !allowLfnstWithMip( cu.firstPU->lumaSize() ) ) || ( cu.tmpFlag && !allowLfnstWithTmp() ) ) ) ||
+#else
+    ( spsIntraLfnstEnabled && CU::isIntra( cu ) && cu.mipFlag && !allowLfnstWithMip( cu.firstPU->lumaSize() ) ) ||
+#endif
+#else
 #if JVET_V0130_INTRA_TMP
     (cu.cs->sps->getUseLFNST() && CU::isIntra(cu) && ((cu.mipFlag && !allowLfnstWithMip(cu.firstPU->lumaSize())) || (cu.tmpFlag && !allowLfnstWithTmp()))) ||
 #else
     (cu.cs->sps->getUseLFNST() && CU::isIntra(cu) && cu.mipFlag && !allowLfnstWithMip(cu.firstPU->lumaSize())) ||
 #endif
+#endif
 #if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
     (CS::isDualITree(*cu.cs) && cu.chType == CHANNEL_TYPE_CHROMA && std::min(cu.blocks[1].width, cu.blocks[1].height) < 4)
 #else
@@ -8606,9 +8624,17 @@ void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx )
 #endif
 
 #if JVET_AG0061_INTER_LFNST_NSPT
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  if( ( spsIntraLfnstEnabled && CU::isIntra( cu ) ) || ( cu.cs->sps->getUseInterLFNST() && CU::isInter( cu ) ) )
+#else
   if (cu.cs->sps->getUseLFNST() && (CU::isIntra(cu) || CU::isInter(cu)))
+#endif
+#else
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  if( spsIntraLfnstEnabled && CU::isIntra( cu ) )
 #else
   if (cu.cs->sps->getUseLFNST() && CU::isIntra(cu))
+#endif
 #endif
   {
 #if INTRA_RM_SMALL_BLOCK_SIZE_CONSTRAINTS
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index cb7aed7c7604e767f013ccdf5b027c16d354f573..eff9b562b6818c873dc4fc89c1aeedae6d6dc22a 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -407,8 +407,17 @@ protected:
   bool      m_SBT;                                ///< Sub-Block Transform for inter blocks
   int       m_SBTFast64WidthTh;                   ///< Enable size-64 SBT in encoder RDO check for HD and above sequences
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool      m_intraLFNSTISlice;
+  bool      m_intraLFNSTPBSlice;
+  bool      m_interLFNST;
+#else
   bool      m_LFNST;
+#endif
   bool      m_useFastLFNST;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool      m_useFastInterLFNST;
+#endif
   bool      m_sbTmvpEnableFlag;
   bool      m_Affine;
   bool      m_AffineType;
@@ -1532,10 +1541,23 @@ public:
   bool      getSubPicIdMappingInSpsFlag                 ()                          { return m_subPicIdMappingInSpsFlag; }
   uint32_t  getSubPicIdLen                              ()                          { return m_subPicIdLen; }
   uint32_t  getSubPicId                                 (int i)                     { return m_subPicId[i]; }
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  void      setIntraLFNSTISlice             ( bool b )       { m_intraLFNSTISlice = b; }
+  bool      getIntraLFNSTISlice()                      const { return m_intraLFNSTISlice; }
+  void      setIntraLFNSTPBSlice            ( bool b )       { m_intraLFNSTPBSlice = b; }
+  bool      getIntraLFNSTPBSlice()                     const { return m_intraLFNSTPBSlice; }
+  void      setInterLFNST                   ( bool b )       { m_interLFNST = b; }
+  bool      getInterLFNST()                            const { return m_interLFNST; }
+#else
   void      setLFNST                        ( bool b )       { m_LFNST = b; }
   bool      getLFNST()                                 const { return m_LFNST; }
+#endif
   void      setUseFastLFNST                 ( bool b )       { m_useFastLFNST = b; }
   bool      getUseFastLFNST()                          const { return m_useFastLFNST; }
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  void      setUseFastInterLFNST            ( bool b )       { m_useFastInterLFNST = b; }
+  bool      getUseFastInterLFNST()                     const { return m_useFastInterLFNST; }
+#endif
 
   void      setUseLMChroma                  ( int n )        { m_LMChroma = n; }
   int       getUseLMChroma()                           const { return m_LMChroma; }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 3398fb01e2e3b4a4fc66e4270b2db771f94c748b..336a73354b6a25c87e9d1c1bae42b17fe7f63a96 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -2530,9 +2530,17 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS
 #endif
 #endif
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsIntraLfnstEnabled = ( ( tempCS->slice->getSliceType() == I_SLICE && sps.getUseIntraLFNSTISlice() ) ||
+                                ( tempCS->slice->getSliceType() != I_SLICE && sps.getUseIntraLFNSTPBSlice() ) );
+#endif
   bool       skipOtherLfnst      = false;
   int        startLfnstIdx       = 0;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  int        endLfnstIdx         = spsIntraLfnstEnabled ? maxLfnstIdx : 0;
+#else
   int        endLfnstIdx         = sps.getUseLFNST() ? maxLfnstIdx : 0;
+#endif
 #if INTRA_TRANS_ENC_OPT
   if (m_pcEncCfg->getIntraPeriod() == 1)
   {
@@ -2545,8 +2553,12 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS
 #endif
 #if JVET_W0103_INTRA_MTS
   int grpNumMax = 1;
+#else
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  int grpNumMax = spsIntraLfnstEnabled ? m_pcEncCfg->getMTSIntraMaxCand() : 1;
 #else
   int grpNumMax = sps.getUseLFNST() ? m_pcEncCfg->getMTSIntraMaxCand() : 1;
+#endif
 #endif
   m_modeCtrl->setISPWasTested(false);
   m_pcIntraSearch->invalidateBestModeCost();
@@ -2794,7 +2806,11 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS
   for( int trGrpIdx = 0; trGrpIdx < grpNumMax; trGrpIdx++ )
   {
     const uint8_t startMtsFlag = trGrpIdx > 0;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    const uint8_t endMtsFlag   = spsIntraLfnstEnabled ? considerMtsSecondPass : 0;
+#else
     const uint8_t endMtsFlag   = sps.getUseLFNST() ? considerMtsSecondPass : 0;
+#endif
 
     if( ( trGrpIdx == 0 || ( !skipSecondMtsPass && considerMtsSecondPass ) ) && trGrpCheck[ trGrpIdx ] )
     {
@@ -2811,7 +2827,11 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS
             continue;
           }
           //3) if interHad is 0, only try further modes if some intra mode was already better than inter
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+          if( spsIntraLfnstEnabled && m_pcEncCfg->getUsePbIntraFast() && !tempCS->slice->isIntra() && bestCU && CU::isInter( *bestCS->getCU( partitioner.chType ) ) && interHad == 0 )
+#else
           if( sps.getUseLFNST() && m_pcEncCfg->getUsePbIntraFast() && !tempCS->slice->isIntra() && bestCU && CU::isInter( *bestCS->getCU( partitioner.chType ) ) && interHad == 0 )
+#endif
           {
             continue;
           }
@@ -3362,7 +3382,11 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS
 
           if( !mtsFlag ) static_cast< double& >( costSize2Nx2NmtsFirstPass ) = tempCS->cost;
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+          if( spsIntraLfnstEnabled && !tempCS->cus.empty() )
+#else
           if( sps.getUseLFNST() && !tempCS->cus.empty() )
+#endif
           {
             skipOtherLfnst = m_modeCtrl->checkSkipOtherLfnst( encTestMode, tempCS, partitioner );
           }
@@ -3385,7 +3409,11 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS
             }
           }
          
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+          if( !spsIntraLfnstEnabled )
+#else
           if( !sps.getUseLFNST() )
+#endif
           {
             xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );
           }
@@ -3465,7 +3493,11 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS
       } //for lfnstIdx
     } //if (!skipSecondMtsPass && considerMtsSecondPass && trGrpCheck[iGrpIdx])
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    if( spsIntraLfnstEnabled && trGrpIdx < 3 )
+#else
     if( sps.getUseLFNST() && trGrpIdx < 3 )
+#endif
     {
       trGrpCheck[ trGrpIdx + 1 ] = false;
 
@@ -21571,7 +21603,11 @@ void EncCu::xEncodeInterResidual(   CodingStructure *&tempCS
 #if JVET_AG0061_INTER_LFNST_NSPT
   cu->lfnstFlag           = false;
   cu->lfnstIdx            = 0;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  const bool lfnstAllowed = tempCS->sps->getUseInterLFNST() && CU::isInter( *cu )
+#else
   const bool lfnstAllowed = tempCS->sps->getUseLFNST() && CU::isInter(*cu)
+#endif
                             && partitioner.currArea().lwidth() <= tempCS->sps->getMaxTbSize()
                             && partitioner.currArea().lheight() <= tempCS->sps->getMaxTbSize();
 #endif
@@ -22016,7 +22052,11 @@ void EncCu::xEncodeInterResidual(   CodingStructure *&tempCS
       bool testLN = true;
       if (bestCost != MAX_DOUBLE && LNOffCost != MAX_DOUBLE)
       {
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+        double th = m_pcEncCfg->getUseFastInterLFNST() ? 1.01 : std::max( ( 1.0 + 1.0 / sqrt( cu->lwidth() * cu->lheight() ) ), 1.07 );
+#else
         double th = std::max((1.0 + 1.0 / sqrt(cu->lwidth() * cu->lheight())), 1.07);
+#endif
         if (!(prevBestLN == 0 || m_LNCostSave == MAX_DOUBLE))
         {
           assert(m_sbtCostSave[1] <= m_LNCostSave);
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index 39e3ee26b9b52b22b6e8fd2a5b8e8592134f3b12..817b49b30043ca29a3715219a89b390f6ef93e8c 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1809,7 +1809,13 @@ void EncLib::xInitSPS( SPS& sps )
   sps.setLog2SignPredArea                    (m_log2SignPredArea);
 #endif
 #endif
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  sps.setUseIntraLFNSTISlice                 ( m_intraLFNSTISlice );
+  sps.setUseIntraLFNSTPBSlice                ( m_intraLFNSTPBSlice );
+  sps.setUseInterLFNST                       ( m_interLFNST );
+#else
   sps.setUseLFNST                            ( m_LFNST );
+#endif
   sps.setSbTMVPEnabledFlag(m_sbTmvpEnableFlag);
   sps.setAMVREnabledFlag                ( m_ImvMode != IMV_OFF );
   sps.setBDOFEnabledFlag                    ( m_BIO );
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index c5a1b6ba21ebf85699a522ca11640f9da5ebedea..6ac68ae8981d9447a93c24416d3181a720e16754 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -743,9 +743,18 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c
   };
 
   CHECK( !cu.firstPU, "CU has no PUs" );
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsIntraLfnstEnabled = ( ( cu.slice->getSliceType() == I_SLICE && cu.cs->sps->getUseIntraLFNSTISlice() ) ||
+                                ( cu.slice->getSliceType() != I_SLICE && cu.cs->sps->getUseIntraLFNSTPBSlice() ) );
+#endif
   // variables for saving fast intra modes scan results across multiple LFNST passes
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool LFNSTLoadFlag = spsIntraLfnstEnabled && cu.lfnstIdx != 0;
+  bool LFNSTSaveFlag = spsIntraLfnstEnabled && cu.lfnstIdx == 0;
+#else
   bool LFNSTLoadFlag = sps.getUseLFNST() && cu.lfnstIdx != 0;
   bool LFNSTSaveFlag = sps.getUseLFNST() && cu.lfnstIdx == 0;
+#endif
 
   LFNSTSaveFlag &= sps.getUseIntraMTS() ? cu.mtsFlag == 0 : true;
 #if JVET_AB0155_SGPM
@@ -772,7 +781,11 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c
   const int maxSizeEMT = MTS_INTRA_MAX_CU_SIZE;
   if( width <= maxSizeEMT && height <= maxSizeEMT && sps.getUseIntraMTS() )
   {
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    mtsUsageFlag = ( spsIntraLfnstEnabled && cu.mtsFlag == 1 ) ? 2 : 1;
+#else
     mtsUsageFlag = ( sps.getUseLFNST() && cu.mtsFlag == 1 ) ? 2 : 1;
+#endif
   }
 
   if( width * height < 64 && !m_pcEncCfg->getUseFastLFNST() )
@@ -845,8 +858,13 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c
     int numTotalPartsVer = (int)height >> floorLog2(CU::getISPSplitDim(width, height, TU_1D_HORZ_SPLIT));
     m_ispTestedModes[0].init( numTotalPartsHor, numTotalPartsVer );
     //the total number of subpartitions is modified to take into account the cases where LFNST cannot be combined with ISP due to size restrictions
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    numTotalPartsHor = spsIntraLfnstEnabled && CU::canUseLfnstWithISP( cu.Y(), HOR_INTRA_SUBPARTITIONS ) ? numTotalPartsHor : 0;
+    numTotalPartsVer = spsIntraLfnstEnabled && CU::canUseLfnstWithISP( cu.Y(), VER_INTRA_SUBPARTITIONS ) ? numTotalPartsVer : 0;
+#else
     numTotalPartsHor = sps.getUseLFNST() && CU::canUseLfnstWithISP(cu.Y(), HOR_INTRA_SUBPARTITIONS) ? numTotalPartsHor : 0;
     numTotalPartsVer = sps.getUseLFNST() && CU::canUseLfnstWithISP(cu.Y(), VER_INTRA_SUBPARTITIONS) ? numTotalPartsVer : 0;
+#endif
     for (int j = 1; j < NUM_LFNST_NUM_PER_SET; j++)
     {
       m_ispTestedModes[j].init(numTotalPartsHor, numTotalPartsVer);
@@ -2750,7 +2768,11 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c
         {
           THROW("Full search not supported for MIP");
         }
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+        if( spsIntraLfnstEnabled && mtsUsageFlag == 1 )
+#else
         if (sps.getUseLFNST() && mtsUsageFlag == 1)
+#endif
         {
           // Store the modes to be checked with RD
           m_savedNumRdModes[lfnstIdx] = numModesForFullRD;
@@ -2864,7 +2886,11 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c
         {
           uiRdModeList.resize(std::min<size_t>(uiRdModeList.size(), maxSize));
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+          if( spsIntraLfnstEnabled && mtsUsageFlag == 1 )
+#else
           if (sps.getUseLFNST() && mtsUsageFlag == 1)
+#endif
           {
             // Update also the number of stored modes to avoid partial fill of mode storage
             m_savedNumRdModes[lfnstIdx] = std::min<int32_t>(int32_t(uiRdModeList.size()), m_savedNumRdModes[lfnstIdx]);
@@ -2895,7 +2921,11 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c
       }
     }
 #if JVET_Y0142_ADAPT_INTRA_MTS
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    if( spsIntraLfnstEnabled && m_modesForMTS.size() == 0 && cu.mtsFlag )
+#else
     if (sps.getUseLFNST() && m_modesForMTS.size() == 0 && cu.mtsFlag)
+#endif
     {
       return false;
     }
@@ -2964,7 +2994,11 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c
     if ( testISP )
     {
       // we reserve positions for ISP in the common full RD list
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      const int maxNumRDModesISP = spsIntraLfnstEnabled ? 16 * NUM_LFNST_NUM_PER_SET : 16;
+#else
       const int maxNumRDModesISP = sps.getUseLFNST() ? 16 * NUM_LFNST_NUM_PER_SET : 16;
+#endif
       m_curIspLfnstIdx = 0;
       for (int i = 0; i < maxNumRDModesISP; i++)
       {
@@ -3422,10 +3456,18 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c
       }
       validReturn |= tmpValidReturn;
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+#if JVET_W0123_TIMD_FUSION
+      if( spsIntraLfnstEnabled && mtsUsageFlag == 1 && !cu.ispMode && mode >= 0 && !cu.timd )
+#else
+      if( spsIntraLfnstEnabled && mtsUsageFlag == 1 && !cu.ispMode && mode >= 0 )
+#endif
+#else
 #if JVET_W0123_TIMD_FUSION
       if( sps.getUseLFNST() && mtsUsageFlag == 1 && !cu.ispMode && mode >= 0 && !cu.timd )
 #else
       if( sps.getUseLFNST() && mtsUsageFlag == 1 && !cu.ispMode && mode >= 0 )
+#endif
 #endif
       {
         m_modeCostStore[lfnstIdx][mode] = tmpValidReturn ? csTemp->cost : (MAX_DOUBLE / 2.0); //(MAX_DOUBLE / 2.0) ??
@@ -3534,13 +3576,21 @@ bool IntraSearch::estIntraPredLumaQT(CodingUnit &cu, Partitioner &partitioner, c
           }
 #endif
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+          if( spsIntraLfnstEnabled && mtsUsageFlag == 1 && !cu.ispMode )
+#else
           if( sps.getUseLFNST() && mtsUsageFlag == 1 && !cu.ispMode )
+#endif
           {
             m_bestModeCostStore[ lfnstIdx ] = csBest->cost; //cs.cost;
             m_bestModeCostValid[ lfnstIdx ] = true;
           }
 #if JVET_W0103_INTRA_MTS
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+          if( spsIntraLfnstEnabled && m_globalBestCostStore > csBest->cost )
+#else
           if (sps.getUseLFNST() && m_globalBestCostStore > csBest->cost)
+#endif
           {
             m_globalBestCostStore = csBest->cost;
             m_globalBestCostValid = true;
@@ -10483,6 +10533,10 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
   }
 
   bool validReturnFull = false;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsIntraLfnstEnabled = ( ( slice.getSliceType() == I_SLICE && sps.getUseIntraLFNSTISlice() ) ||
+                                ( slice.getSliceType() != I_SLICE && sps.getUseIntraLFNSTPBSlice() ) );
+#endif
 
   if( bCheckFull )
   {
@@ -10495,7 +10549,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
     const bool mtsAllowed = CU::isMTSAllowed( cu, COMPONENT_Y );
     std::vector<TrMode> trModes;
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    if( spsIntraLfnstEnabled )
+#else
     if( sps.getUseLFNST() )
+#endif
     {
       checkTransformSkip &= tsAllowed;
       checkTransformSkip &= !cu.mtsFlag;
@@ -10557,12 +10615,21 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
     Distortion singleDistTmpLuma = 0;
     uint64_t     singleTmpFracBits = 0;
     double     singleCostTmp     = 0;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    int        firstCheckId      = ( spsIntraLfnstEnabled && mtsCheckRangeFlag && cu.mtsFlag ) ? mtsFirstCheckId : 0;
+
+    //we add the MTS candidates to the loop. TransformSkip will still be the last one to be checked (when modeId == lastCheckId) as long as checkTransformSkip is true
+    int        lastCheckId       = spsIntraLfnstEnabled ? ( ( mtsCheckRangeFlag && cu.mtsFlag ) ? ( mtsLastCheckId + ( int ) checkTransformSkip ) : ( numTransformIndexCands - ( firstCheckId + 1 ) + ( int ) checkTransformSkip ) ) :
+                                   trModes[ nNumTransformCands - 1 ].first;
+    bool isNotOnlyOneMode        = spsIntraLfnstEnabled ? lastCheckId != firstCheckId : nNumTransformCands != 1;
+#else
     int        firstCheckId      = ( sps.getUseLFNST() && mtsCheckRangeFlag && cu.mtsFlag ) ? mtsFirstCheckId : 0;
 
     //we add the MTS candidates to the loop. TransformSkip will still be the last one to be checked (when modeId == lastCheckId) as long as checkTransformSkip is true
     int        lastCheckId       = sps.getUseLFNST() ? ( ( mtsCheckRangeFlag && cu.mtsFlag ) ? ( mtsLastCheckId + ( int ) checkTransformSkip ) : ( numTransformIndexCands - ( firstCheckId + 1 ) + ( int ) checkTransformSkip ) ) :
                                    trModes[ nNumTransformCands - 1 ].first;
     bool isNotOnlyOneMode        = sps.getUseLFNST() ? lastCheckId != firstCheckId : nNumTransformCands != 1;
+#endif
 
     if( isNotOnlyOneMode )
     {
@@ -10580,7 +10647,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
     bool    cbfBestModeValid = false;
     bool    cbfDCT2  = true;
 #if JVET_W0103_INTRA_MTS
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    if( spsIntraLfnstEnabled && cu.mtsFlag )
+#else
     if (sps.getUseLFNST() && cu.mtsFlag)
+#endif
     {
       xSelectAMTForFullRD(tu
 #if JVET_AG0136_INTRA_TMP_LIC
@@ -10591,11 +10662,19 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
 #endif
     double bestDCT2cost = MAX_DOUBLE;
     double threshold = m_pcEncCfg->getUseFastISP() && !cu.ispMode && ispIsCurrentWinner && nNumTransformCands > 1 ? 1 + 1.4 / sqrt( cu.lwidth() * cu.lheight() ) : 1;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    for( int modeId = firstCheckId; modeId <= ( spsIntraLfnstEnabled ? lastCheckId : ( nNumTransformCands - 1 ) ); modeId++ )
+#else
     for( int modeId = firstCheckId; modeId <= ( sps.getUseLFNST() ? lastCheckId : ( nNumTransformCands - 1 ) ); modeId++ )
+#endif
     {
       uint8_t transformIndex = modeId;
 #if JVET_W0103_INTRA_MTS
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      if( spsIntraLfnstEnabled && cu.mtsFlag )
+#else
       if (sps.getUseLFNST() && cu.mtsFlag)
+#endif
       {
         if (modeId >= m_numCandAMTForFullRD)
         {
@@ -10607,7 +10686,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
       m_validMTSReturn = true;
 #endif
 #endif
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      if( spsIntraLfnstEnabled )
+#else
       if( sps.getUseLFNST() )
+#endif
       {
         if( ( transformIndex < lastCheckId ) || ( ( transformIndex == lastCheckId ) && !checkTransformSkip ) ) //we avoid this if the mode is transformSkip
         {
@@ -10649,13 +10732,21 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
       int default0Save1Load2 = 0;
       singleDistTmpLuma = 0;
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      if( modeId == firstCheckId && ( spsIntraLfnstEnabled ? ( modeId != lastCheckId ) : ( nNumTransformCands > 1 ) ) )
+#else
       if( modeId == firstCheckId && ( sps.getUseLFNST() ? ( modeId != lastCheckId ) : ( nNumTransformCands > 1 ) ) )
+#endif
       {
         default0Save1Load2 = 1;
       }
       else if (modeId != firstCheckId)
       {
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+        if( spsIntraLfnstEnabled && !cbfBestModeValid )
+#else
         if( sps.getUseLFNST() && !cbfBestModeValid )
+#endif
         {
           default0Save1Load2 = 1;
         }
@@ -10668,7 +10759,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
       {
         default0Save1Load2 = 0;
       }
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      if( spsIntraLfnstEnabled )
+#else
       if( sps.getUseLFNST() )
+#endif
       {
         if( cu.mtsFlag )
         {
@@ -10777,7 +10872,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
 #endif
 
       //----- determine rate and r-d cost -----
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      if( ( spsIntraLfnstEnabled ? ( modeId == lastCheckId && modeId != 0 && checkTransformSkip ) : ( trModes[ modeId ].first != 0 ) ) && !TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ) )
+#else
       if( ( sps.getUseLFNST() ? ( modeId == lastCheckId && modeId != 0 && checkTransformSkip ) : ( trModes[ modeId ].first != 0 ) ) && !TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ) )
+#endif
       {
         //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden.
         if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless())
@@ -10850,7 +10949,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
         bestDCT2cost = singleCostTmp;
       }
 #if JVET_W0103_INTRA_MTS
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      if( spsIntraLfnstEnabled && cu.mtsFlag )
+#else
       if (sps.getUseLFNST() && cu.mtsFlag)
+#endif
       {
         if (singleCostTmp != MAX_DOUBLE)
         {
@@ -10879,7 +10982,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
         uiSingleDistLuma  = singleDistTmpLuma;
         singleFracBits    = singleTmpFracBits;
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+        if( spsIntraLfnstEnabled )
+#else
         if( sps.getUseLFNST() )
+#endif
         {
           bestModeId[ COMPONENT_Y ] = modeId;
           cbfBestMode = TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth );
@@ -10916,7 +11023,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
       }
     }
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    if( spsIntraLfnstEnabled && !validReturnFull )
+#else
     if( sps.getUseLFNST() && !validReturnFull )
+#endif
     {
       csFull->cost = MAX_DOUBLE;
 
@@ -10992,7 +11103,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
 #endif
 #endif
       subTuCounter += subTuCounter != -1 ? 1 : 0;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      if( spsIntraLfnstEnabled && !tmpValidReturnSplit )
+#else
       if( sps.getUseLFNST() && !tmpValidReturnSplit )
+#endif
       {
         splitIsSelected = false;
         break;
@@ -11070,7 +11185,11 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
   bool retVal = false;
   if( csFull || csSplit )
   {
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    if( !spsIntraLfnstEnabled || validReturnFull || validReturnSplit )
+#else
     if( !sps.getUseLFNST() || validReturnFull || validReturnSplit )
+#endif
     {
       // otherwise this would've happened in useSubStructure
 #if JVET_Z0118_GDR
@@ -11119,6 +11238,10 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
   }
 
   bool validReturnFull = false;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsIntraLfnstEnabled = ( ( slice.getSliceType() == I_SLICE && sps.getUseIntraLFNSTISlice() ) ||
+                                ( slice.getSliceType() != I_SLICE && sps.getUseIntraLFNSTPBSlice() ) );
+#endif
 
   if (bCheckFull)
   {
@@ -11225,7 +11348,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
     const bool mtsAllowed = CU::isMTSAllowed(cu, COMPONENT_Y);
     std::vector<TrMode> trModes;
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    if( spsIntraLfnstEnabled )
+#else
     if (sps.getUseLFNST())
+#endif
     {
       checkTransformSkip &= tsAllowed;
       checkTransformSkip &= !cu.mtsFlag;
@@ -11276,9 +11403,15 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
     Distortion      singleDistTmpLuma = 0;
     uint64_t        singleTmpFracBits = 0;
     double          singleCostTmp = 0;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    int             firstCheckId = ( spsIntraLfnstEnabled && mtsCheckRangeFlag && cu.mtsFlag ) ? mtsFirstCheckId : 0;
+    int             lastCheckId = spsIntraLfnstEnabled ? ( ( mtsCheckRangeFlag && cu.mtsFlag ) ? ( mtsLastCheckId + ( int ) checkTransformSkip ) : ( numTransformIndexCands - ( firstCheckId + 1 ) + ( int ) checkTransformSkip ) ) : trModes[ nNumTransformCands - 1 ].first;
+    bool            isNotOnlyOneMode = spsIntraLfnstEnabled ? lastCheckId != firstCheckId : nNumTransformCands != 1;
+#else
     int             firstCheckId = (sps.getUseLFNST() && mtsCheckRangeFlag && cu.mtsFlag) ? mtsFirstCheckId : 0;
     int             lastCheckId = sps.getUseLFNST() ? ((mtsCheckRangeFlag && cu.mtsFlag) ? (mtsLastCheckId + (int)checkTransformSkip) : (numTransformIndexCands - (firstCheckId + 1) + (int)checkTransformSkip)) : trModes[nNumTransformCands - 1].first;
     bool            isNotOnlyOneMode = sps.getUseLFNST() ? lastCheckId != firstCheckId : nNumTransformCands != 1;
+#endif
 
     if (isNotOnlyOneMode)
     {
@@ -11302,7 +11435,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
       m_CABACEstimator->getCtx() = ctxStart;
       m_CABACEstimator->resetBits();
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      if( spsIntraLfnstEnabled )
+#else
       if (sps.getUseLFNST())
+#endif
       {
         if ((transformIndex < lastCheckId) || ((transformIndex == lastCheckId) && !checkTransformSkip)) //we avoid this if the mode is transformSkip
         {
@@ -11330,7 +11467,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
       }
 
       singleDistTmpLuma = 0;
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      if( spsIntraLfnstEnabled )
+#else
       if (sps.getUseLFNST())
+#endif
       {
         if (cu.mtsFlag)
         {
@@ -11406,7 +11547,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
       cuCtx.isDQPCoded = true;
       cuCtx.isChromaQpAdjCoded = true;
       //----- determine rate and r-d cost -----
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      if( ( spsIntraLfnstEnabled ? ( modeId == lastCheckId && modeId != 0 && checkTransformSkip ) : ( trModes[ modeId ].first != 0 ) ) && !TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ) )
+#else
       if ((sps.getUseLFNST() ? (modeId == lastCheckId && modeId != 0 && checkTransformSkip) : (trModes[modeId].first != 0)) && !TU::getCbfAtDepth(tu, COMPONENT_Y, currDepth))
+#endif
       {
         //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden.
         if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless())
@@ -11449,7 +11594,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
         dSingleCostLuma = singleCostTmp;
         validReturnFull = true;
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+        if( spsIntraLfnstEnabled )
+#else
         if (sps.getUseLFNST())
+#endif
         {
           bestLumaModeId = modeId;
           cbfBestMode = TU::getCbfAtDepth(tu, COMPONENT_Y, currDepth);
@@ -11475,7 +11624,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
     if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING || !slice.isLossless())
     m_pcRdCost->lambdaAdjustColorTrans(false, COMPONENT_Y);
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    if( spsIntraLfnstEnabled )
+#else
     if (sps.getUseLFNST())
+#endif
     {
       if (!validReturnFull)
       {
@@ -11885,7 +12038,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
     do
     {
       bool tmpValidReturnSplit = xRecurIntraCodingACTQT(*csSplit, partitioner, mtsCheckRangeFlag, mtsFirstCheckId, mtsLastCheckId, moreProbMTSIdxFirst);
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+      if( spsIntraLfnstEnabled )
+#else
       if (sps.getUseLFNST())
+#endif
       {
         if (!tmpValidReturnSplit)
         {
@@ -11930,7 +12087,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
   bool retVal = false;
   if (csFull || csSplit)
   {
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+    if( spsIntraLfnstEnabled )
+#else
     if (sps.getUseLFNST())
+#endif
     {
       if (validReturnFull || validReturnSplit)
       {
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 56dcc142ef9dd781ceb6fc98f38f84acea4b8cf7..31d954c68cd4188f8686ee548fff4295ac6b980a 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -1273,8 +1273,14 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
     }
 #endif
   }
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  WRITE_FLAG( pcSPS->getUseIntraLFNSTISlice() ? 1 : 0, "sps_intra_lfnst_intra_slice_enabled_flag" );
+  WRITE_FLAG( pcSPS->getUseIntraLFNSTPBSlice() ? 1 : 0, "sps_intra_lfnst_inter_slice_enabled_flag" );
+  WRITE_FLAG( pcSPS->getUseInterLFNST() ? 1 : 0, "sps_inter_lfnst_enabled_flag" );
+#else
   WRITE_FLAG(pcSPS->getUseLFNST() ? 1 : 0, "sps_lfnst_enabled_flag");
 #endif
+#endif
 
 #if JVET_S0052_RM_SEPARATE_COLOUR_PLANE
   if (pcSPS->getChromaFormatIdc() != CHROMA_400)
@@ -1884,8 +1890,14 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
   }
 #if !JVET_S0074_SPS_REORDER
   WRITE_FLAG(pcSPS->getUseLmcs() ? 1 : 0, "sps_lmcs_enable_flag");
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  WRITE_FLAG( pcSPS->getUseIntraLFNSTISlice() ? 1 : 0, "sps_intra_lfnst_intra_slice_enabled_flag" );
+  WRITE_FLAG( pcSPS->getUseIntraLFNSTPBSlice() ? 1 : 0, "sps_intra_lfnst_inter_slice_enabled_flag" );
+  WRITE_FLAG( pcSPS->getUseInterLFNST() ? 1 : 0, "sps_inter_lfnst_enabled_flag" );
+#else
   WRITE_FLAG( pcSPS->getUseLFNST() ? 1 : 0,                                                    "sps_lfnst_enabled_flag" );
 #endif
+#endif
 #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET
   WRITE_FLAG( pcSPS->getLadfEnabled() ? 1 : 0,                                                 "sps_ladf_enabled_flag" );
   if ( pcSPS->getLadfEnabled() )
@@ -1924,7 +1936,13 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
   // KJS: remove scaling lists?
   WRITE_FLAG( pcSPS->getScalingListFlag() ? 1 : 0,                                   "sps_explicit_scaling_list_enabled_flag" );
 
+#if JVET_AH0103_LOW_DELAY_LFNST_NSPT
+  bool spsLfnstEnabled = ( pcSPS->getUseIntraLFNSTISlice() || pcSPS->getUseIntraLFNSTPBSlice() );
+  spsLfnstEnabled |= pcSPS->getUseInterLFNST();
+  if( spsLfnstEnabled && pcSPS->getScalingListFlag() )
+#else
   if (pcSPS->getUseLFNST() && pcSPS->getScalingListFlag())
+#endif
   {
     WRITE_FLAG(pcSPS->getDisableScalingMatrixForLfnstBlks(), "scaling_matrix_for_lfnst_disabled_flag");
   }