diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index 66d4b611c92bbbf1e082aa11e416472c60f3c4e0..bd9f28465e6dae6314c570b5422f2f9da85e11d1 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -173,6 +173,9 @@ static const int MAX_VPS_NUH_RESERVED_ZERO_LAYER_ID_PLUS1 =         1;
 static const int MAXIMUM_INTRA_FILTERED_WIDTH =                    16;
 static const int MAXIMUM_INTRA_FILTERED_HEIGHT =                   16;
 
+#if JVET_N0178_IMPLICIT_BDOF_SPLIT
+static const int MAX_BDOF_APPLICATION_REGION =                     16;
+#endif
 
 static const int MAX_CPB_CNT =                                     32; ///< Upper bound of (cpb_cnt_minus1 + 1)
 static const int MAX_NUM_LAYER_IDS =                               64;
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index ac3e9785b12989d190a39c5fc154737b0faa3ae1..7d472ce3cfe4dbd24e121ab845e37c6f61db8dd9 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -366,7 +366,50 @@ void InterPrediction::xSubPuMC( PredictionUnit& pu, PelUnitBuf& predBuf, const R
 
   pu.cu->affine = isAffine;
 }
+#if JVET_N0178_IMPLICIT_BDOF_SPLIT
+void InterPrediction::xSubPuBio(PredictionUnit& pu, PelUnitBuf& predBuf, const RefPicList &eRefPicList /*= REF_PIC_LIST_X*/)
+{
+  // compute the location of the current PU
+  Position puPos = pu.lumaPos();
+  Size puSize = pu.lumaSize();
 
+  PredictionUnit subPu;
+
+  subPu.cs = pu.cs;
+  subPu.cu = pu.cu;
+  subPu.mergeType = pu.mergeType;
+  subPu.mmvdMergeFlag = pu.mmvdMergeFlag;
+  subPu.mmvdEncOptMode = pu.mmvdEncOptMode;
+  subPu.mergeFlag = pu.mergeFlag;
+  subPu.mvRefine = pu.mvRefine;
+  subPu.refIdx[0] = pu.refIdx[0];
+  subPu.refIdx[1] = pu.refIdx[1];
+  int  fstStart = puPos.y;
+  int  secStart = puPos.x;
+  int  fstEnd = puPos.y + puSize.height;
+  int  secEnd = puPos.x + puSize.width;
+  int  fstStep = std::min((int)MAX_BDOF_APPLICATION_REGION, (int)puSize.height);
+  int  secStep = std::min((int)MAX_BDOF_APPLICATION_REGION, (int)puSize.width);
+  for (int fstDim = fstStart; fstDim < fstEnd; fstDim += fstStep)
+  {
+    for (int secDim = secStart; secDim < secEnd; secDim += secStep)
+    {
+      int x = secDim;
+      int y = fstDim;
+      int dx = secStep;
+      int dy = fstStep;
+
+      const MotionInfo &curMi = pu.getMotionInfo(Position{ x, y });
+
+      subPu.UnitArea::operator=(UnitArea(pu.chromaFormat, Area(x, y, dx, dy)));
+      subPu = curMi;
+      PelUnitBuf subPredBuf = predBuf.subBuf(UnitAreaRelative(pu, subPu));
+
+      motionCompensation(subPu, subPredBuf, eRefPicList);
+    }
+  }
+}
+#endif
 void InterPrediction::xChromaMC(PredictionUnit &pu, PelUnitBuf& pcYuvPred)
 {
   // separated tree, chroma
@@ -1164,6 +1207,52 @@ void InterPrediction::motionCompensation( PredictionUnit &pu, PelUnitBuf &predBu
   }
   else
   {
+
+#if JVET_N0178_IMPLICIT_BDOF_SPLIT
+    bool bioApplied = false;
+    const Slice &slice = *pu.cs->slice;
+    if (pu.cs->sps->getBDOFEnabledFlag())
+    {
+
+      if (pu.cu->affine || m_subPuMC)
+      {
+        bioApplied = false;
+      }
+      else
+      {
+        const bool biocheck0 = !(pps.getWPBiPred() && slice.getSliceType() == B_SLICE);
+        const bool biocheck1 = !(pps.getUseWP() && slice.getSliceType() == P_SLICE);
+        if (biocheck0
+          && biocheck1
+          && PU::isBiPredFromDifferentDir(pu)
+          && !(pu.Y().height == 4 || (pu.Y().width == 4 && pu.Y().height == 8))
+          )
+        {
+          bioApplied = true;
+        }
+      }
+
+      if (bioApplied && pu.cu->smvdMode) 
+	  {
+        bioApplied = false;
+      }
+      if (pu.cu->cs->sps->getUseGBi() && bioApplied && pu.cu->GBiIdx != GBI_DEFAULT) 
+	  {
+        bioApplied = false;
+      }
+      if (pu.mmvdEncOptMode == 2 && pu.mmvdMergeFlag) 
+	  {
+        bioApplied = false;
+      }
+    }
+    bool dmvrApplied = false;
+    dmvrApplied = (pu.mvRefine) && PU::checkDMVRCondition(pu);
+    if ((pu.lumaSize().width > MAX_BDOF_APPLICATION_REGION || pu.lumaSize().height > MAX_BDOF_APPLICATION_REGION) && pu.mergeType != MRG_TYPE_SUBPU_ATMVP && (bioApplied && !dmvrApplied))
+    {
+      xSubPuBio(pu, predBuf, eRefPicList);
+    }
+    else
+#endif
     if (pu.mergeType != MRG_TYPE_DEFAULT_N && pu.mergeType != MRG_TYPE_IBC)
     {
       xSubPuMC( pu, predBuf, eRefPicList );
diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h
index 56b45faa2e72a52c99c526c191a492c71ad7687a..760e2268a27fb1831f5bc10f15e0592f6d3791b7 100644
--- a/source/Lib/CommonLib/InterPrediction.h
+++ b/source/Lib/CommonLib/InterPrediction.h
@@ -144,6 +144,9 @@ protected:
   static bool xCheckIdenticalMotion( const PredictionUnit& pu );
 
   void xSubPuMC(PredictionUnit& pu, PelUnitBuf& predBuf, const RefPicList &eRefPicList = REF_PIC_LIST_X);
+#if JVET_N0178_IMPLICIT_BDOF_SPLIT
+  void xSubPuBio(PredictionUnit& pu, PelUnitBuf& predBuf, const RefPicList &eRefPicList = REF_PIC_LIST_X);
+#endif
   void destroy();
 
 
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 4dbba77683e561f7df7199c01f278aa800028813..64a0cfb68763056f3700b93634963027207d2c39 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -73,6 +73,8 @@
 
 #define JVET_N0271_SIMPLFIED_CCLM                         1 // Simplified CCLM parameter derivation in JVET-N0271
 
+#define JVET_N0178_IMPLICIT_BDOF_SPLIT                    1
+
 #define JCTVC_Y0038_PARAMS                                1
 
 #define JVET_MMVD_OFF_MACRO                               0