diff --git a/cfg/multi-layer/layer1_gop_randomaccess.cfg b/cfg/multi-layer/layer1_gop_randomaccess.cfg
index 1d511c107421da1dc0b95e80c1378f9869edeca9..5d0201351ab8916c1bc29622a79578d504ce8d89 100644
--- a/cfg/multi-layer/layer1_gop_randomaccess.cfg
+++ b/cfg/multi-layer/layer1_gop_randomaccess.cfg
@@ -1,4 +1,5 @@
 #======== Coding Structure =============
+EncInterLayerOpt              : 1           # RDO adjustments for inter-layer prediction (see JVET-AJ0225)
 ExplicitILRP                  : 1           # Explicit configuration of inter-layer reference pictures (0:disabled, 1:enabled)
 DecodingRefreshType           : 1           # Random Accesss 0:none, 1:CRA, 2:IDR, 3:Recovery Point SEI
 GOPSize                       : 32          # GOP Size (number of B slice = GOPSize-1)
diff --git a/doc/software-manual.tex b/doc/software-manual.tex
index a5e5fbbc08033781b14b691bf55ccdb1688698f9..0ef2482461f831975cd73941850a82e231e91da7 100644
--- a/doc/software-manual.tex
+++ b/doc/software-manual.tex
@@ -1743,6 +1743,19 @@ inter-layer reference pictures are no longer inserted automatically.
 \par
 \\
 
+\Option{EncInterLayerOpt} &
+%\ShortOption{\None} &
+\Default{false} &
+Enables or disables the encoder optimization to favor inter-layer predictions.
+\\
+
+\Option{EncInterLayerOptLambdaModifier} &
+%\ShortOption{\None} &
+\Default{0.1} &
+Specifies a value that is multiplied with the Lagrange multiplier
+$\lambda$, for use in the modified rate-distortion cost calculation when comparing inter-layer with intra-layer modes (only used if EncInterLayerOpt is enabled).
+\\
+
 \Option{LayerId\emph{i}} &
 %\ShortOption{\None} &
 \Default{0} &
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 026a1a64f125cc1669932464b43874a041485759..2b28c3994fccb8af223494c4f8248c7caeb8ccfc 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -302,6 +302,8 @@ void EncApp::xInitLibCfg( int layerIdx )
   m_cEncLib.setValidFrames(m_firstValidFrame, m_lastValidFrame);
   m_cEncLib.setAvoidIntraInDepLayer                              ( m_avoidIntraInDepLayer );
   m_cEncLib.setExplicitILRP                                      ( m_explicitILRP );
+  m_cEncLib.setEncILOpt                                          ( m_encILOpt );
+  m_cEncLib.setEncILOptLambdaModifier                            ( m_encILOptLambdaModifier );
 
   m_cEncLib.setRefLayerMetricsEnabled(m_refMetricsEnabled);
   m_cEncLib.setRefLayerRescaledAvailable(false);
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index 7dbd3c3f335857e3a72afba7e4cf98f7624a7f14..0a043300926296deaaafe914bd5e641ce3317854 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1788,6 +1788,8 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ( "MaxTidILRefPicsPlusOneLayerId%d",                m_maxTidILRefPicsPlus1Str, std::string(""), MAX_VPS_LAYERS, "Maximum temporal ID for inter-layer reference pictures plus 1 of i-th layer, 0 for IRAP only")
   ( "RPLofDepLayerInSH",                              m_rplOfDepLayerInSh,                      false, "define Reference picture lists in slice header instead of SPS for dependant layers")
   ( "ExplicitILRP",                                   m_explicitILRP,                           false, "Explicitly define Inter-Layer Reference pictures in GOP entry")
+  ( "EncInterLayerOpt",                               m_encILOpt,                               false, "Enable encoder optimization to favor inter-layer predictions")
+  ( "EncInterLayerOptLambdaModifier",                 m_encILOptLambdaModifier,         ( double )0.1, "lambda modifier for modified RD cost in Inter-Layer criterion")
     ;
 
   opts.addOptions()
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 851d0a8dc8c58bc61bec6550569f1bc6126c09fb..44684e4baa009539f3761f492ed072513130e167 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -1093,6 +1093,8 @@ protected:
   bool        m_allIndependentLayersFlag;
   std::string m_predDirectionArray;
   bool        m_explicitILRP;
+  bool        m_encILOpt;
+  double      m_encILOptLambdaModifier;
 
   int         m_numRefLayers[MAX_VPS_LAYERS];
   std::string m_refLayerIdxStr[MAX_VPS_LAYERS];
diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp
index b74fe434d30c65a2837e5dd39fd8fe73dd88e42e..a7e4e37073c80a01ac1d61ccf2657d104a592400 100644
--- a/source/Lib/CommonLib/CodingStructure.cpp
+++ b/source/Lib/CommonLib/CodingStructure.cpp
@@ -1583,6 +1583,7 @@ void CodingStructure::initSubStructure( CodingStructure& subStruct, const Channe
 
   subStruct.useDbCost = false;
   subStruct.costDbOffset = 0;
+  subStruct.useInterlayerRef = false;
 
   for( uint32_t i = 0; i < subStruct.area.blocks.size(); i++ )
   {
@@ -1716,6 +1717,7 @@ void CodingStructure::useSubStructure( const CodingStructure& subStruct, const C
     dist     += subStruct.dist;
     cost     += subStruct.cost;
     costDbOffset += subStruct.costDbOffset;
+    useInterlayerRef |= subStruct.useInterlayerRef;
   }
   if( parent )
   {
@@ -1776,6 +1778,8 @@ void CodingStructure::copyStructure( const CodingStructure& other, const Channel
   dist     = other.dist;
   cost     = other.cost;
   costDbOffset = other.costDbOffset;
+  useInterlayerRef = other.useInterlayerRef;
+
   CHECKD( area != other.area, "Incompatible sizes" );
 
   const UnitArea dualITreeArea = CS::getArea( *this, this->area, chType );
@@ -1894,6 +1898,7 @@ void CodingStructure::initStructData( const int &QP, const bool &skipMotBuf )
   costDbOffset = 0;
   useDbCost = false;
   interHad = std::numeric_limits<Distortion>::max();
+  useInterlayerRef = false;
 }
 
 
diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h
index 131694459a3943958b8db960bd4999e2f5f3c54b..226e5171158fe09511e65ee75db593859f0d2f7a 100644
--- a/source/Lib/CommonLib/CodingStructure.h
+++ b/source/Lib/CommonLib/CodingStructure.h
@@ -192,6 +192,7 @@ public:
   bool        useDbCost;
   double      costDbOffset;
   double      lumaCost;
+  bool        useInterlayerRef;
   uint64_t    fracBits;
   Distortion  dist;
   Distortion  interHad;
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index bb2a7f0340d146d4158232ba3a77f4a9311c6af3..43cb2bbf5b8565d304f75b679c374770b0ee2ca9 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -705,6 +705,18 @@ CMotionBuf PredictionUnit::getMotionBuf() const
   return cs->getMotionBuf( *this );
 }
 
+bool PredictionUnit::checkUseInterLayerRef() const
+{
+  bool useInterLayerRef=false;
+  for( uint32_t i = 0; i < NUM_REF_PIC_LIST_01; i++ )
+  {
+    if (refIdx[i] >= 0)
+    {
+      useInterLayerRef |= cu->slice->getRpl(RefPicList(i))->isInterLayerRefPic(refIdx[i]);
+    }
+  }
+  return useInterLayerRef;
+}
 
 // ---------------------------------------------------------------------------
 // transform unit method definitions
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index 1c8187b8ae7bba91482ea24fb5a272e7700f9934..ea2716f7180fa8258bd626ec341c12bbe0716aa1 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -458,6 +458,7 @@ struct PredictionUnit : public UnitArea, public IntraPredictionData, public Inte
   MotionBuf         getMotionBuf();
   CMotionBuf        getMotionBuf() const;
 
+  bool checkUseInterLayerRef() const;
   bool isAffineBlock() const {return cu->affine && mergeType != MergeType::SUBPU_ATMVP;}
 };
 
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index a4d30dd887ecaa4debc6aa89dc60f5fdf7d0bb81..6e33719182c9e15356a53d570d072521e4cf0395 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -1138,6 +1138,8 @@ protected:
   bool        m_rprRASLtoolSwitch;
   bool        m_refLayerMetricsEnabled;
   bool        m_explicitILRP;
+  bool        m_encILOpt;
+  double      m_encILOptLambdaModifier;
   
 public:
   EncCfg()
@@ -3131,6 +3133,10 @@ public:
   bool        getAvoidIntraInDepLayer()                        const { return m_avoidIntraInDepLayer; }
   void        setExplicitILRP(bool b)                        { m_explicitILRP = b; }
   bool        getExplicitILRP()                        const { return m_explicitILRP; }
+  void        setEncILOpt(bool b)                            { m_encILOpt = b; }
+  bool        getEncILOpt()                            const { return m_encILOpt; }
+  void        setEncILOptLambdaModifier(double dValue)       { m_encILOptLambdaModifier = dValue; }
+  double      getEncILOptLambdaModifier()              const { return m_encILOptLambdaModifier; }
 
   const EncCfgParam::CfgVPSParameters &getVPSParameters() const
   {
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index edbc18f6a846aab7c819d2cf4dc95d3fabae56eb..cca83bc0e597dbab31839be5fe562ac2f3d68fa2 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -1152,7 +1152,10 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS,
   const double cost = costTemp;
 
   m_CABACEstimator->getCtx() = SubCtx(Ctx::ctxPartition, ctxStart);
-  if (cost > bestCS->cost + bestCS->costDbOffset
+  if ((cost > bestCS->cost + bestCS->costDbOffset
+       && (!m_pcEncCfg->getEncILOpt()
+           || tempCS->slice->getRpl(REF_PIC_LIST_0)->getNumberOfInterLayerPictures() + tempCS->slice->getRpl(REF_PIC_LIST_1)->getNumberOfInterLayerPictures() == 0
+           || bestCS->useInterlayerRef))
 #if ENABLE_QPA_SUB_CTU
     || (m_pcEncCfg->getUsePerceptQPA() && !m_pcEncCfg->getUseRateCtrl() && pps.getUseDQP() && (slice.getCuQpDeltaSubdiv() > 0) && (split == CU_HORZ_SPLIT || split == CU_VERT_SPLIT) &&
         (currDepth == 0)) // force quad-split or no split at CTU level
@@ -2274,6 +2277,10 @@ void EncCu::xCheckRDCostUnifiedMerge(CodingStructure *&tempCS, CodingStructure *
 
   // 1. Pass: get SATD-cost for selected candidates and reduce their count
   m_mergeItemList.resetList(numMergeSatdCand);
+  if (m_pcEncCfg->getEncILOpt())
+  {
+    m_mergeItemList.resetBackupList(1);
+  }
   const TempCtx ctxStart(m_ctxPool, m_CABACEstimator->getCtx());
   DistParam distParam;
   const bool bUseHadamard = !tempCS->slice->getDisableSATDForRD();
@@ -2304,6 +2311,11 @@ void EncCu::xCheckRDCostUnifiedMerge(CodingStructure *&tempCS, CodingStructure *
     addGpmCandsToPruningList(gpmMergeCtx, localUnitArea, sqrtLambdaForFirstPass, ctxStart, comboList, geoBuffer, distParam, pu);
   }
 
+  if (m_pcEncCfg->getEncILOpt())
+  {
+    m_mergeItemList.insertBackupItemsToList();
+  }
+
   // Try to limit number of candidates using SATD-costs
   const double threshold = m_mergeItemList.getMergeItemInList(0)->cost * MRG_FAST_RATIO;
   numMergeSatdCand = updateRdCheckingNum(threshold, numMergeSatdCand);
@@ -2775,6 +2787,10 @@ void EncCu::generateMergePrediction(const UnitArea& unitArea, MergeItem* mergeIt
   CHECK((luma && mergeItem->lumaPredReady) || (chroma && mergeItem->chromaPredReady), "Prediction has been avaiable");
   // update Pu info
   mergeItem->exportMergeInfo(pu, forceNoResidual);
+  if (!finalRd)
+  {
+    mergeItem->useInterLayerRef = pu.checkUseInterLayerRef();
+  }
 
   switch (mergeItem->mergeItemType)
   {
@@ -2884,6 +2900,7 @@ double EncCu::calcLumaCost4MergePrediction(const TempCtx& ctxStart, const PelUni
 unsigned int EncCu::updateRdCheckingNum(double threshold, unsigned int numMergeSatdCand)
 {
   numMergeSatdCand = std::min(numMergeSatdCand, (unsigned int) m_mergeItemList.size());
+  int numMergeSatdCandOrig = numMergeSatdCand;
 
   for (uint32_t i = 0; i < numMergeSatdCand; i++)
   {
@@ -2894,6 +2911,20 @@ unsigned int EncCu::updateRdCheckingNum(double threshold, unsigned int numMergeS
       break;
     }
   }
+
+  if (m_pcEncCfg->getEncILOpt())
+  {
+    for (uint32_t i = numMergeSatdCand; i < numMergeSatdCandOrig; i++)
+    {
+      const auto mergeItem = m_mergeItemList.getMergeItemInList(i);
+      if (mergeItem->useInterLayerRef)
+      {
+        m_mergeItemList.swapItems(i, numMergeSatdCand);
+        ++numMergeSatdCand;
+      }
+    }
+  }
+
   return numMergeSatdCand;
 }
 
@@ -2962,7 +2993,7 @@ void EncCu::addRegularCandsToPruningList(const MergeCtx& mergeCtx, const UnitAre
         regularMerge->cost = MAX_DOUBLE;
       }
     }
-    m_mergeItemList.insertMergeItemToList(regularMerge);
+    m_mergeItemList.insertMergeItemToList(regularMerge, m_pcEncCfg->getEncILOpt());
   }
   m_pcInterSearch->xDmvrSetEncoderCheckFlag(false);
 }
@@ -3018,7 +3049,7 @@ void EncCu::addCiipCandsToPruningList(const MergeCtx& mergeCtx, const UnitArea&
     {
       ciipMerge->cost = calcLumaCost4MergePrediction(ctxStart, dstBuf, sqrtLambdaForFirstPassIntra, *pu, distParam);
     }
-    m_mergeItemList.insertMergeItemToList(ciipMerge);
+    m_mergeItemList.insertMergeItemToList(ciipMerge, m_pcEncCfg->getEncILOpt());
   }
 }
 
@@ -3040,7 +3071,7 @@ void EncCu::addMmvdCandsToPruningList(const MergeCtx& mergeCtx, const UnitArea&
     auto dstBuf = mmvdMerge->getPredBuf(localUnitArea);
     generateMergePrediction(localUnitArea, mmvdMerge, *pu, true, false, dstBuf, false, false, nullptr, nullptr);
     mmvdMerge->cost = calcLumaCost4MergePrediction(ctxStart, dstBuf, sqrtLambdaForFirstPassIntra, *pu, distParam);
-    m_mergeItemList.insertMergeItemToList(mmvdMerge);
+    m_mergeItemList.insertMergeItemToList(mmvdMerge, m_pcEncCfg->getEncILOpt());
   }
 }
 
@@ -3088,7 +3119,7 @@ void EncCu::addAffineCandsToPruningList(AffineMergeCtx& affineMergeCtx, const Un
       }
     }
 #endif
-    m_mergeItemList.insertMergeItemToList(mergeItem);
+    m_mergeItemList.insertMergeItemToList(mergeItem, m_pcEncCfg->getEncILOpt());
   }
 }
 
@@ -3109,7 +3140,7 @@ void EncCu::addGpmCandsToPruningList(const MergeCtx& mergeCtx, const UnitArea& l
     generateMergePrediction(localUnitArea, mergeItem, *pu, true, false, dstBuf, false, false,
       geoBuffer[mergeIdxPair[0]], geoBuffer[mergeIdxPair[1]]);
     mergeItem->cost = calcLumaCost4MergePrediction(ctxStart, dstBuf, sqrtLambdaForFirstPass, *pu, distParamSAD2);
-    m_mergeItemList.insertMergeItemToList(mergeItem);
+    m_mergeItemList.insertMergeItemToList(mergeItem, m_pcEncCfg->getEncILOpt());
   }
 }
 
@@ -4087,6 +4118,11 @@ void EncCu::xEncodeInterResidual(CodingStructure *&tempCS, CodingStructure *&bes
     }
   }
 
+  if (m_pcEncCfg->getEncILOpt())
+  {
+    tempCS->useInterlayerRef = pu.checkUseInterLayerRef();
+  }
+
   const bool mtsAllowed = tempCS->sps->getExplicitMtsInterEnabled() && CU::isInter(*cu)
                           && partitioner.currArea().lwidth() <= MTS_INTER_MAX_CU_SIZE
                           && partitioner.currArea().lheight() <= MTS_INTER_MAX_CU_SIZE;
@@ -4506,6 +4542,10 @@ void EncCu::xReuseCachedResult( CodingStructure *&tempCS, CodingStructure *&best
     tempCS->dist     = finalDistortion;
     tempCS->fracBits = m_CABACEstimator->getEstFracBits();
     tempCS->cost     = m_pcRdCost->calcRdCost( tempCS->fracBits, tempCS->dist );
+    if (m_pcEncCfg->getEncILOpt())
+    {
+      tempCS->useInterlayerRef = cu.firstPU->checkUseInterLayerRef();
+    }
 
     xEncodeDontSplit( *tempCS,         partitioner );
     xCheckDQP       ( *tempCS,         partitioner );
@@ -4542,6 +4582,7 @@ void MergeItem::create(ChromaFormat chromaFormat, const Area& area)
   bcwIdx = 0;
   interDir = 0;
   useAltHpelIf = false;
+  useInterLayerRef = false;
   affineType = AffineModel::_4_PARAMS;
   mergeItemType = MergeItemType::NUM;
 
@@ -4755,12 +4796,18 @@ MergeItemList::~MergeItemList()
   {
     m_mergeItemPool.giveBack(p);
   }
+  for (auto p : m_backupList)
+  {
+    m_mergeItemPool.giveBack(p);
+  }
   m_list.clear();
+  m_backupList.clear();
 }
 
 void MergeItemList::init(size_t maxSize, ChromaFormat chromaFormat, int ctuWidth, int ctuHeight)
 {
   m_list.reserve(maxSize + 1); // to avoid reallocation when inserting a new item
+  m_backupList.reserve(2);
   m_chromaFormat = chromaFormat;
   m_ctuArea.x = 0;
   m_ctuArea.y = 0;
@@ -4776,25 +4823,41 @@ MergeItem* MergeItemList::allocateNewMergeItem()
   return p;
 }
 
-void MergeItemList::insertMergeItemToList(MergeItem* p)
+void MergeItemList::insertMergeItemToList(MergeItem* p, bool trackInterLayerCand)
 {
   if (m_list.empty())
   {
     m_list.push_back(p);
+    m_numInterLayers += (trackInterLayerCand && p->useInterLayerRef) ? 1 : 0;
   }
   else if (m_list.size() == m_maxTrackingNum && p->cost >= m_list.back()->cost)
   {
-    m_mergeItemPool.giveBack(p);
+    if (trackInterLayerCand && p->useInterLayerRef && m_numInterLayers < m_maxTrackingBackupNum)
+    {
+      insertMergeItemToBackupList(p);
+    }
+    else
+    {
+      m_mergeItemPool.giveBack(p);
+    }
   }
   else
   {
     if (m_list.size() == m_maxTrackingNum)
     {
-      m_mergeItemPool.giveBack(m_list.back());
+      if (trackInterLayerCand && m_list.back()->useInterLayerRef && (--m_numInterLayers) < m_maxTrackingBackupNum)
+      {
+        insertMergeItemToBackupList(m_list.back());
+      }
+      else
+      {
+        m_mergeItemPool.giveBack(m_list.back());
+      }
       m_list.pop_back();
     }
     auto it = std::find_if(m_list.begin(), m_list.end(), [&p](const MergeItem *mi) { return p->cost < mi->cost; });
     m_list.insert(it, p);
+    m_numInterLayers += (trackInterLayerCand && p->useInterLayerRef) ? 1 : 0;
   }
 }
 
@@ -4812,6 +4875,78 @@ void MergeItemList::resetList(size_t maxTrackingNum)
   m_list.clear();
   m_list.reserve(maxTrackingNum);
   m_maxTrackingNum = maxTrackingNum;
+  m_numInterLayers = 0;
+}
+
+
+
+void MergeItemList::insertMergeItemToBackupList(MergeItem* p)
+{
+  if (m_backupList.empty())
+  {
+    m_backupList.push_back(p);
+  }
+  else if (m_backupList.size() == m_maxTrackingBackupNum && p->cost >= m_backupList.back()->cost)
+  {
+    m_mergeItemPool.giveBack(p);
+  }
+  else
+  {
+    if (m_backupList.size() == m_maxTrackingBackupNum)
+    {
+      m_mergeItemPool.giveBack(m_backupList.back());
+      m_backupList.pop_back();
+    }
+    auto it = std::find_if(m_backupList.begin(), m_backupList.end(), [&p](const MergeItem *mi) { return p->cost < mi->cost; });
+    m_backupList.insert(it, p);
+  }
+}
+
+void MergeItemList::resetBackupList(size_t maxTrackingBackupNum)
+{
+  for (auto p : m_backupList)
+  {
+    m_mergeItemPool.giveBack(p);
+  }
+  m_backupList.clear();
+  m_backupList.reserve(2*maxTrackingBackupNum-1);
+  m_maxTrackingBackupNum = maxTrackingBackupNum;
+}
+
+void MergeItemList::insertBackupItemsToList()
+{
+  if (m_backupList.size() == 0 || m_numInterLayers >= m_maxTrackingBackupNum)
+  {
+    return;
+  }
+
+  size_t backupSize          = m_backupList.size();
+  size_t maxNumReplacedItems = std::min(m_backupList.size(), m_maxTrackingBackupNum - m_numInterLayers);
+  int    numReplacedItems    = 0;
+  while ( numReplacedItems < maxNumReplacedItems && m_list.size()>0 )
+  {
+    if (m_list.back()->useInterLayerRef)
+    {
+      m_backupList.push_back(m_list.back()); //temporarily insert in backup
+      m_list.pop_back();
+    }
+    else
+    {
+      m_mergeItemPool.giveBack(m_list.back());
+      m_list.pop_back();
+      ++numReplacedItems;
+    }
+  }
+
+  m_list.insert( m_list.end(), m_backupList.begin() + backupSize, m_backupList.end() );         //re-insert IL items temporarily placed in backup list.
+  m_list.insert( m_list.end(), m_backupList.begin(), m_backupList.begin() + numReplacedItems ); //insert IL item initially in backup in replacement of removed non-IL items.
+  m_numInterLayers += numReplacedItems;
+
+  for (int i = 0; i < m_backupList.size() - numReplacedItems; i++)
+  {
+    m_mergeItemPool.giveBack(m_backupList.back());
+  }
+  m_backupList.clear();
 }
 
 //! \}
diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h
index 1ce9eb0eaf48f6754597e6082f57906818c08b2c..5927c13d5467084063ac982a8f1055ee84e4562c 100644
--- a/source/Lib/EncoderLib/EncCu.h
+++ b/source/Lib/EncoderLib/EncCu.h
@@ -161,6 +161,7 @@ public:
   uint8_t       bcwIdx;
   uint8_t       interDir;
   bool          useAltHpelIf;
+  bool          useInterLayerRef;
   AffineModel   affineType;
 
   bool          noResidual;
@@ -205,6 +206,9 @@ private:
   Pool<MergeItem> m_mergeItemPool;
   std::vector<MergeItem *> m_list;
   size_t m_maxTrackingNum = 0;
+  std::vector<MergeItem *> m_backupList;
+  size_t m_maxTrackingBackupNum = 0;
+  int m_numInterLayers = 0;
   ChromaFormat  m_chromaFormat;
   Area m_ctuArea;
 
@@ -214,11 +218,17 @@ public:
 
   void          init(size_t maxSize, ChromaFormat chromaFormat, int ctuWidth, int ctuHeight);
   MergeItem*    allocateNewMergeItem();
-  void          insertMergeItemToList(MergeItem* p);
+  void          insertMergeItemToList(MergeItem* p, bool trackInterLayerCand=false);
   void          resetList(size_t maxTrackingNum);
   MergeItem*    getMergeItemInList(size_t index);
   size_t        size() { return m_list.size(); }
 
+  void          insertMergeItemToBackupList(MergeItem* p);
+  void          resetBackupList(size_t maxTrackingBackupNum);
+  void          insertBackupItemsToList();
+  void          swapItems(int index_first, int index_second) { std::swap(m_list[index_first], m_list[index_second]); }
+  int           getNumInterLayerItems() { return m_numInterLayers; }
+
 };
 
 class EncCu
diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp
index fb6de020b3aa51aa9d9b7dfd3c4a31ba782559f3..aaf3ee9db9a94c464056370045132d9eb3fede9d 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.cpp
+++ b/source/Lib/EncoderLib/EncModeCtrl.cpp
@@ -2268,8 +2268,36 @@ bool EncModeCtrlMTnoRQT::useModeResult( const EncTestMode& encTestmode, CodingSt
       }
     }
   }
-  // for now just a simple decision based on RD-cost or choose tempCS if bestCS is not yet coded
-  if( tempCS->features[ENC_FT_RD_COST] != MAX_DOUBLE && ( !cuECtx.bestCS || ( ( tempCS->features[ENC_FT_RD_COST] + ( tempCS->useDbCost ? tempCS->costDbOffset : 0 ) ) < ( cuECtx.bestCS->features[ENC_FT_RD_COST] + ( tempCS->useDbCost ? cuECtx.bestCS->costDbOffset : 0 ) ) ) ) )
+
+  bool chooseTemp = false;
+  if( tempCS->features[ENC_FT_RD_COST] != MAX_DOUBLE )
+  {
+    if(!cuECtx.bestCS)
+    {
+      chooseTemp = true;
+    }
+    else
+    {
+      // for now just a simple decision based on RD-cost or choose tempCS if bestCS is not yet coded
+      chooseTemp = ( tempCS->features[ENC_FT_RD_COST] + ( tempCS->useDbCost ? tempCS->costDbOffset : 0 ) ) < ( cuECtx.bestCS->features[ENC_FT_RD_COST] + ( tempCS->useDbCost ? cuECtx.bestCS->costDbOffset : 0 ) );
+
+      // Adjust criterion to choose mode with inter-layer prediction if it has lower modified RD cost with lambda modifier (regardless of original RD cost).
+      if (m_pcEncCfg->getEncILOpt() && tempCS->useInterlayerRef != cuECtx.bestCS->useInterlayerRef)
+      {
+        const double costTemp = m_pcRdCost->calcRdCost(uint64_t(tempCS->features[ENC_FT_FRAC_BITS] * m_pcEncCfg->getEncILOptLambdaModifier()), tempCS->dist);
+        const double costBest = m_pcRdCost->calcRdCost(uint64_t(cuECtx.bestCS->features[ENC_FT_FRAC_BITS] * m_pcEncCfg->getEncILOptLambdaModifier()), cuECtx.bestCS->dist);
+        if (tempCS->useInterlayerRef && costTemp < costBest)
+        {
+          chooseTemp = true;
+        }
+        else if (!tempCS->useInterlayerRef && costBest < costTemp)
+        {
+          chooseTemp = false;
+        }
+      }
+    }
+  }
+  if (chooseTemp)
   {
     cuECtx.bestCS = tempCS;
     cuECtx.bestCU = tempCS->cus[0];