Enforce `DataModel::Provider` everywhere (#36319)

* Pass 1: remove a large set of ifdefs

* More flags removes

* Remove more flags

* More flags removes

* Clean up a few more builders

* Clean up references from ember compatibility functions and make the data model implementation of reporting and attribute path expand iterator be the only implemented versions

* Remove ServerClusterCommandExists

* Remove ConcreteAttributePathExists

* Remove ReadSingleClusterData

* Remove GetAttributeMetadata

* Even more cleanup

* Remove invalid include

* Update target test file: we removed all DM enable/disable

* Add back endif

* Cleanup targets for building

* Cleanup unused target

* one more unused function removal

* Fix up one condition

* Restyled by clang-format

* Update src/app/AttributePathExpandIterator.h

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Update src/app/AttributePathExpandIterator.h

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Update src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAccessControl.mm

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Add back missed code

* Restyled by clang-format

* Update src/app/tests/BUILD.gn

Co-authored-by: Junior Martinez <67972863+jmartinez-silabs@users.noreply.github.com>

---------

Co-authored-by: Andrei Litvin <andreilitvin@google.com>
Co-authored-by: Restyled.io <commits@restyled.io>
Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
Co-authored-by: Junior Martinez <67972863+jmartinez-silabs@users.noreply.github.com>
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index af102bf..210106c 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -76,7 +76,7 @@
               with:
                   languages: "cpp"
             - name: Setup Build
-              run: scripts/build/gn_gen.sh --args="chip_config_memory_debug_checks=true chip_config_memory_debug_dmalloc=false chip_data_model_check_die_on_failure=true"
+              run: scripts/build/gn_gen.sh --args="chip_config_memory_debug_checks=true chip_config_memory_debug_dmalloc=false"
             - name: Run Build
               run: scripts/run_in_build_env.sh "ninja -C ./out"
             - name: Run Tests
@@ -183,7 +183,7 @@
                   scripts/run_in_build_env.sh "ninja -C ./out/$BUILD_TYPE"
             - name: Setup Build, Run Build and Run Tests
               run: |
-                  BUILD_TYPE=gcc_release scripts/build/gn_gen.sh --args="is_debug=false chip_data_model_check_die_on_failure=true"
+                  BUILD_TYPE=gcc_release scripts/build/gn_gen.sh --args="is_debug=false"
                   scripts/run_in_build_env.sh "ninja -C ./out/gcc_release"
                   BUILD_TYPE=gcc_release scripts/tests/gn_tests.sh
             - name: Clean output
@@ -205,14 +205,14 @@
                       esac
 
                       rm -rf ./out/sanitizers
-                      BUILD_TYPE=sanitizers scripts/build/gn_gen.sh --args="$GN_ARGS chip_data_model_check_die_on_failure=true" --export-compile-commands
+                      BUILD_TYPE=sanitizers scripts/build/gn_gen.sh --args="$GN_ARGS" --export-compile-commands
                       BUILD_TYPE=sanitizers scripts/tests/gn_tests.sh
                   done
             - name: Generate tests with sanitizers (for tidy)
               if: github.event.pull_request.number != null
               run: |
                   rm -rf ./out/sanitizers
-                  BUILD_TYPE=sanitizers scripts/build/gn_gen.sh --args="is_clang=true is_asan=true chip_data_model_check_die_on_failure=true" --export-compile-commands
+                  BUILD_TYPE=sanitizers scripts/build/gn_gen.sh --args="is_clang=true is_asan=true" --export-compile-commands
             - name: Ensure codegen is done for sanitize
               run: |
                   ./scripts/run_in_build_env.sh "./scripts/run_codegen_targets.sh out/sanitizers"
@@ -333,7 +333,7 @@
 
             - name: Setup Build, Run Build and Run Tests
               run: |
-                  scripts/build/gn_gen.sh --args="enable_rtti=true chip_config_memory_debug_checks=false chip_config_memory_debug_dmalloc=false chip_generate_link_map_file=false chip_data_model_check_die_on_failure=true"
+                  scripts/build/gn_gen.sh --args="enable_rtti=true chip_config_memory_debug_checks=false chip_config_memory_debug_dmalloc=false chip_generate_link_map_file=false"
                   scripts/run_in_build_env.sh "ninja -C ./out"
                   scripts/tests/gn_tests.sh
             - name: Setup test python environment
@@ -439,7 +439,7 @@
                   # We want to build various standalone example apps (similar to what examples-linux-standalone.yaml
                   # does), so use target_os="all" to get those picked up as part of the "unified" build.  But then
                   # to save CI resources we want to exclude the "host clang" build, which uses the pigweed clang.
-                  scripts/build/gn_gen.sh --args='target_os="all" is_asan=true enable_host_clang_build=false chip_data_model_check_die_on_failure=true' --export-compile-commands
+                  scripts/build/gn_gen.sh --args='target_os="all" is_asan=true enable_host_clang_build=false' --export-compile-commands
                   scripts/run_in_build_env.sh "ninja -C ./out/$BUILD_TYPE"
                   scripts/tests/gn_tests.sh
             - name: Ensure codegen is done for default
diff --git a/.github/workflows/examples-linux-arm.yaml b/.github/workflows/examples-linux-arm.yaml
index 78a1c8d..5aeeb4d 100644
--- a/.github/workflows/examples-linux-arm.yaml
+++ b/.github/workflows/examples-linux-arm.yaml
@@ -65,7 +65,7 @@
                         --target linux-arm64-chip-tool-nodeps-ipv6only \
                         --target linux-arm64-lock-clang \
                         --target linux-arm64-minmdns-clang \
-                        --target linux-arm64-light-data-model-enabled-rpc-ipv6only-clang \
+                        --target linux-arm64-light-rpc-ipv6only-clang \
                         --target linux-arm64-thermostat-no-ble-clang \
                         --target linux-arm64-lit-icd-no-ble-clang \
                         --target linux-arm64-fabric-admin-clang-rpc \
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 68bf4b0..2471529 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -114,8 +114,6 @@
                      --known-failure app/util/config.h \
                      --known-failure app/util/DataModelHandler.cpp \
                      --known-failure app/util/DataModelHandler.h \
-                     --known-failure app/util/ember-compatibility-functions.cpp \
-                     --known-failure app/util/ember-compatibility-functions.h \
                      --known-failure app/util/ember-global-attribute-access-interface.h \
                      --known-failure app/util/ember-io-storage.h \
                      --known-failure app/util/endpoint-config-api.h \
@@ -299,7 +297,6 @@
                       ':(exclude)src/app/dynamic_server/DynamicDispatcher.cpp'                               \
                       ':(exclude)src/app/util/attribute-table.cpp'                                           \
                       ':(exclude)src/app/util/attribute-table.h'                                             \
-                      ':(exclude)src/app/util/ember-compatibility-functions.cpp'                             \
                       ':(exclude)src/app/util/mock/CodegenEmberMocks.cpp'                                    \
                       ':(exclude)src/app/zap-templates/templates/app/attributes/Accessors-src.zapt'          \
                       ':(exclude)src/darwin/Framework/CHIP/ServerEndpoint/MTRIMDispatch.mm'                  \
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 63957b6..77c31b8 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -487,7 +487,7 @@
                   scripts/run_in_build_env.sh './scripts/build_python.sh --install_virtual_env out/venv'
                   ./scripts/run_in_build_env.sh \
                    "./scripts/build/build_examples.py \
-                      --target linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test-data-model-check-check-failure-die \
+                      --target linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test \
                       --target linux-x64-lock-ipv6only-no-ble-no-wifi-tsan-clang-test \
                       --target linux-x64-lit-icd-ipv6only-no-ble-no-wifi-tsan-clang-test \
                       --target linux-x64-energy-management-ipv6only-no-ble-no-wifi-tsan-clang-test \
@@ -504,7 +504,7 @@
             - name: Generate an argument environment file
               run: |
                   echo -n "" >/tmp/test_env.yaml
-                  echo "ALL_CLUSTERS_APP: out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test-data-model-check-check-failure-die/chip-all-clusters-app" >> /tmp/test_env.yaml
+                  echo "ALL_CLUSTERS_APP: out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app" >> /tmp/test_env.yaml
                   echo "CHIP_LOCK_APP: out/linux-x64-lock-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-lock-app" >> /tmp/test_env.yaml
                   echo "ENERGY_MANAGEMENT_APP: out/linux-x64-energy-management-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-energy-management-app" >> /tmp/test_env.yaml
                   echo "LIT_ICD_APP: out/linux-x64-lit-icd-ipv6only-no-ble-no-wifi-tsan-clang-test/lit-icd-app" >> /tmp/test_env.yaml
@@ -523,7 +523,7 @@
                   mkdir -p out/trace_data
                   scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/controller/python/test/test_scripts/mobile-device-test.py'
                   scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/execute_python_tests.py --env-file /tmp/test_env.yaml --search-directory src/python_testing'
-                  scripts/run_in_python_env.sh out/venv './scripts/tests/TestTimeSyncTrustedTimeSourceRunner.py --all-clusters out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test-data-model-check-check-failure-die/chip-all-clusters-app'
+                  scripts/run_in_python_env.sh out/venv './scripts/tests/TestTimeSyncTrustedTimeSourceRunner.py --all-clusters out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app'
                   scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestIdChecks.py'
                   scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestSpecParsingDeviceType.py'
                   scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestConformanceSupport.py'
diff --git a/.github/workflows/unit_integration_test.yaml b/.github/workflows/unit_integration_test.yaml
index b51dfaa..1cc0213 100644
--- a/.github/workflows/unit_integration_test.yaml
+++ b/.github/workflows/unit_integration_test.yaml
@@ -74,7 +74,7 @@
                      *) ;;
                   esac
 
-                  scripts/build/gn_gen.sh --args="$GN_ARGS chip_data_model_check_die_on_failure=true"
+                  scripts/build/gn_gen.sh --args="$GN_ARGS"
             - name: Run Build
               run: scripts/run_in_build_env.sh "ninja -C out/$BUILD_TYPE"
             - name: Run Tests
diff --git a/build/chip/esp32/esp32_codegen.cmake b/build/chip/esp32/esp32_codegen.cmake
index 9148912..9cbd839 100644
--- a/build/chip/esp32/esp32_codegen.cmake
+++ b/build/chip/esp32/esp32_codegen.cmake
@@ -71,15 +71,7 @@
 
     add_dependencies(${COMPONENT_LIB} app-zapgen)
     target_include_directories(${COMPONENT_LIB} PUBLIC "${APP_TEMPLATE_GEN_DIR}")
-    target_sources(${COMPONENT_LIB} PRIVATE ${APP_TEMPLATE_GEN_FILES})
-
-    # When data model interface is used, provide a default code-generation data model as
-    # part of zapgen. See `chip_data_model.cmake` for similar logic
-    set(CHIP_DATA_MODEL_INTERFACE "enabled" CACHE STRING "Data model interface option to use: enabled or disabled")
-
-    if ("${CHIP_DATA_MODEL_INTERFACE}" STREQUAL "enabled")
-      target_sources(${COMPONENT_LIB} PRIVATE ${CODEGEN_DATA_MODEL_SOURCES})
-    endif()
+    target_sources(${COMPONENT_LIB} PRIVATE ${APP_TEMPLATE_GEN_FILES} ${CODEGEN_DATA_MODEL_SOURCES})
 
   endif()
 endmacro()
diff --git a/config/common/cmake/chip_gn_args.cmake b/config/common/cmake/chip_gn_args.cmake
index 8fde49c..7d86d1f 100644
--- a/config/common/cmake/chip_gn_args.cmake
+++ b/config/common/cmake/chip_gn_args.cmake
@@ -171,7 +171,6 @@
         LIB_PW_RPC
         DEVICE_INFO_EXAMPLE_PROVIDER
         PROJECT_CONFIG
-        DATA_MODEL_INTERFACE
     )
     set(multiValueArgs
         PROJECT_CONFIG_INC_DIR
@@ -204,10 +203,6 @@
         matter_add_gn_arg_bool      ("chip_build_example_providers" ${ARG_DEVICE_INFO_EXAMPLE_PROVIDER})
     endif() # ARG_DEVICE_INFO_EXAMPLE_PROVIDER
 
-    if (ARG_DATA_MODEL_INTERFACE)
-        matter_add_gn_arg_string("chip_use_data_model_interface"  "${ARG_DATA_MODEL_INTERFACE}")
-    endif()
-
     if (ARG_PROJECT_CONFIG)
         get_filename_component(PROJECT_CONFIG
             ${ARG_PROJECT_CONFIG}
diff --git a/config/esp32/components/chip/CMakeLists.txt b/config/esp32/components/chip/CMakeLists.txt
index f203657..ddf4d72 100644
--- a/config/esp32/components/chip/CMakeLists.txt
+++ b/config/esp32/components/chip/CMakeLists.txt
@@ -33,8 +33,6 @@
 
 set(CHIP_REQUIRE_COMPONENTS esp_eth freertos lwip bt mbedtls fatfs app_update console openthread nvs_flash spi_flash)
 
-set(CHIP_DATA_MODEL_INTERFACE "enabled" CACHE STRING "Data model interface option to use: enabled or disabled")
-
 if(NOT "${IDF_TARGET}" STREQUAL "esp32h2")
     list(APPEND CHIP_REQUIRE_COMPONENTS mdns)
 endif()
@@ -66,12 +64,6 @@
     endif()
 endmacro()
 
-if ("${CHIP_DATA_MODEL_INTERFACE}" STREQUAL "enabled")
-    chip_gn_arg_append("chip_use_data_model_interface" "\"enabled\"")
-else()
-    chip_gn_arg_append("chip_use_data_model_interface" "\"disabled\"")
-endif()
-
 # ESP-IDF lets user set software version string by two ways:
 # 1. Project's CMakeLists.txt file and 2. Config option
 # It depends on CONFIG_APP_PROJECT_VER_FROM_CONFIG option
diff --git a/config/mbed/CMakeLists.txt b/config/mbed/CMakeLists.txt
index e74127b..88567b6 100644
--- a/config/mbed/CMakeLists.txt
+++ b/config/mbed/CMakeLists.txt
@@ -112,9 +112,6 @@
     matter_add_flags(-DMBED_BSD_SOCKET_TRACE=1)
 endif()
 
-# Option can be set with `-DCHIP_DATA_MODEL_INTERFACE=enabled` or similar on the command line
-set(CHIP_DATA_MODEL_INTERFACE "enabled" CACHE STRING "Data model interface option to use: enabled or disabled")
-
 # ==============================================================================
 # Generate configuration for CHIP GN build system
 # ==============================================================================
@@ -124,7 +121,6 @@
     LIB_TESTS       CONFIG_CHIP_BUILD_TESTS
     LIB_PW_RPC      CONFIG_CHIP_PW_RPC
     PROJECT_CONFIG  ${CONFIG_CHIP_PROJECT_CONFIG}
-    DATA_MODEL_INTERFACE ${CHIP_DATA_MODEL_INTERFACE}
 )
 if (CONFIG_CHIP_PW_RPC)
     matter_add_gn_arg_import("${GN_ROOT_TARGET}/lib/pw_rpc/pw_rpc.gni")
diff --git a/config/nrfconnect/chip-module/CMakeLists.txt b/config/nrfconnect/chip-module/CMakeLists.txt
index b3180fd..448287f 100644
--- a/config/nrfconnect/chip-module/CMakeLists.txt
+++ b/config/nrfconnect/chip-module/CMakeLists.txt
@@ -106,13 +106,6 @@
 
 get_property(CHIP_COMPILER_LAUNCHER GLOBAL PROPERTY RULE_LAUNCH_COMPILE)
 
-
-if (CONFIG_USE_CHIP_DATA_MODEL_INTERFACE)
-    set(DATA_MODEL_INTERFACE "enabled")
-else()
-    set(DATA_MODEL_INTERFACE "disabled")
-endif()
-
 # ==============================================================================
 # Generate configuration for CHIP GN build system
 # ==============================================================================
@@ -123,7 +116,6 @@
     LIB_TESTS       CONFIG_CHIP_BUILD_TESTS
     PROJECT_CONFIG  ${CONFIG_CHIP_PROJECT_CONFIG}
     DEVICE_INFO_EXAMPLE_PROVIDER CONFIG_CHIP_EXAMPLE_DEVICE_INFO_PROVIDER
-    DATA_MODEL_INTERFACE ${DATA_MODEL_INTERFACE}
 )
 matter_add_gn_arg_string("zephyr_ar"                              ${CMAKE_AR})
 matter_add_gn_arg_string("zephyr_cc"                              ${CMAKE_C_COMPILER})
diff --git a/config/nxp/chip-cmake-freertos/CMakeLists.txt b/config/nxp/chip-cmake-freertos/CMakeLists.txt
index 517d353..a3c59dc 100644
--- a/config/nxp/chip-cmake-freertos/CMakeLists.txt
+++ b/config/nxp/chip-cmake-freertos/CMakeLists.txt
@@ -50,12 +50,6 @@
 matter_add_gn_arg_bool("nxp_enable_matter_cli" CONFIG_CHIP_LIB_SHELL)
 matter_add_gn_arg_bool("chip_enable_pairing_autostart" CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART)
 
-if (CONFIG_USE_CHIP_DATA_MODEL_INTERFACE)
-    set(DATA_MODEL_INTERFACE "enabled")
-else()
-    set(DATA_MODEL_INTERFACE "disabled")
-endif()
-
 if(CONFIG_BOOTLOADER_MCUBOOT)
     matter_add_gn_arg_bool("no_mcuboot" false)
 endif(CONFIG_BOOTLOADER_MCUBOOT)
@@ -73,7 +67,6 @@
         PROJECT_CONFIG ${CONFIG_CHIP_PROJECT_CONFIG}
         PROJECT_CONFIG_INC_DIR ${CONFIG_CHIP_PROJECT_CONFIG_INCLUDE_DIRS}
         DEVICE_INFO_EXAMPLE_PROVIDER CONFIG_CHIP_EXAMPLE_DEVICE_INFO_PROVIDER
-        DATA_MODEL_INTERFACE ${DATA_MODEL_INTERFACE}
     )
 endif()
 
diff --git a/config/nxp/chip-module/CMakeLists.txt b/config/nxp/chip-module/CMakeLists.txt
index 5024672..6689486 100644
--- a/config/nxp/chip-module/CMakeLists.txt
+++ b/config/nxp/chip-module/CMakeLists.txt
@@ -91,13 +91,6 @@
 
 get_property(CHIP_COMPILER_LAUNCHER GLOBAL PROPERTY RULE_LAUNCH_COMPILE)
 
-if (CONFIG_USE_CHIP_DATA_MODEL_INTERFACE)
-    set(DATA_MODEL_INTERFACE "enabled")
-else()
-    set(DATA_MODEL_INTERFACE "disabled")
-endif()
-
-
 # ==============================================================================
 # Generate configuration for CHIP GN build system
 # ==============================================================================
@@ -108,7 +101,6 @@
     LIB_TESTS       CONFIG_CHIP_BUILD_TESTS
     PROJECT_CONFIG  ${CONFIG_CHIP_PROJECT_CONFIG}
     DEVICE_INFO_EXAMPLE_PROVIDER CONFIG_CHIP_EXAMPLE_DEVICE_INFO_PROVIDER
-    DATA_MODEL_INTERFACE ${DATA_MODEL_INTERFACE}
 )
 matter_add_gn_arg_string("zephyr_ar"                              ${CMAKE_AR})
 matter_add_gn_arg_string("zephyr_cc"                              ${CMAKE_C_COMPILER})
diff --git a/config/telink/chip-module/CMakeLists.txt b/config/telink/chip-module/CMakeLists.txt
index bfc26ce..7490cc4 100644
--- a/config/telink/chip-module/CMakeLists.txt
+++ b/config/telink/chip-module/CMakeLists.txt
@@ -77,12 +77,6 @@
     zephyr_set_openthread_config(${CHIP_OPENTHREAD_CONFIG})
 endif()
 
-if (CONFIG_USE_CHIP_DATA_MODEL_INTERFACE)
-    set(DATA_MODEL_INTERFACE "enabled")
-else()
-    set(DATA_MODEL_INTERFACE "disabled")
-endif()
-
 # ==============================================================================
 # Generate configuration for CHIP GN build system
 # ==============================================================================
@@ -93,7 +87,6 @@
     LIB_TESTS       CONFIG_CHIP_BUILD_TESTS
     PROJECT_CONFIG  ${CONFIG_CHIP_PROJECT_CONFIG}
     DEVICE_INFO_EXAMPLE_PROVIDER CONFIG_CHIP_EXAMPLE_DEVICE_INFO_PROVIDER
-    DATA_MODEL_INTERFACE ${DATA_MODEL_INTERFACE}
 )
 matter_add_gn_arg_string("zephyr_ar"                              ${CMAKE_AR})
 matter_add_gn_arg_string("zephyr_cc"                              ${CMAKE_C_COMPILER})
diff --git a/config/zephyr/Kconfig b/config/zephyr/Kconfig
index c98628e..d8717a6 100644
--- a/config/zephyr/Kconfig
+++ b/config/zephyr/Kconfig
@@ -581,12 +581,4 @@
 	  If CHIP_BLE_EXT_ADVERTISING is set to false, the maximum duration time is 15 minutes, 
 	  else the maximum duration time can be extended to 2880 minutes (48h).
 
-config USE_CHIP_DATA_MODEL_INTERFACE
-    bool "Use a DataModel::Provider interface for data access"
-    default y
-    help
-      This enables a level of indiraction in the CHIP interaction model engine in 
-      accessing underlying data and executing operations such as 
-      wildcard-expansion, read, write and invoke.
-
 endif
diff --git a/config/zephyr/chip-module/CMakeLists.txt b/config/zephyr/chip-module/CMakeLists.txt
index fb94465..3461a97 100644
--- a/config/zephyr/chip-module/CMakeLists.txt
+++ b/config/zephyr/chip-module/CMakeLists.txt
@@ -70,12 +70,6 @@
         zephyr_set_openthread_config(${CHIP_OPENTHREAD_CONFIG})
     endif()
 
-    if (CONFIG_USE_CHIP_DATA_MODEL_INTERFACE)
-        set(DATA_MODEL_INTERFACE "enabled")
-    else()
-        set(DATA_MODEL_INTERFACE "disabled")
-    endif()
-
     # ==============================================================================
     # Generate configuration for CHIP GN build system
     # ==============================================================================
@@ -84,7 +78,6 @@
         LIB_SHELL CONFIG_CHIP_LIB_SHELL
         LIB_TESTS CONFIG_CHIP_BUILD_TESTS
         PROJECT_CONFIG ${CONFIG_CHIP_PROJECT_CONFIG}
-        DATA_MODEL_INTERFACE ${DATA_MODEL_INTERFACE}
     )
 
     matter_add_gn_arg_string("zephyr_ar" ${CMAKE_AR})
diff --git a/examples/common/pigweed/rpc_services/Attributes.h b/examples/common/pigweed/rpc_services/Attributes.h
index d34d7e5..99e348e 100644
--- a/examples/common/pigweed/rpc_services/Attributes.h
+++ b/examples/common/pigweed/rpc_services/Attributes.h
@@ -23,23 +23,19 @@
 
 #include <app-common/zap-generated/attribute-type.h>
 #include <app/AppConfig.h>
+#include <app/AttributeValueEncoder.h>
 #include <app/InteractionModelEngine.h>
 #include <app/MessageDef/AttributeReportIBs.h>
+#include <app/data-model-provider/ActionReturnStatus.h>
+#include <app/data-model-provider/OperationTypes.h>
+#include <app/data-model-provider/Provider.h>
 #include <app/util/attribute-storage.h>
 #include <app/util/attribute-table.h>
-#include <app/util/ember-compatibility-functions.h>
 #include <lib/core/TLV.h>
 #include <lib/core/TLVTags.h>
 #include <lib/core/TLVTypes.h>
 #include <platform/PlatformManager.h>
 
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-#include <app/AttributeValueEncoder.h>
-#include <app/data-model-provider/ActionReturnStatus.h>
-#include <app/data-model-provider/OperationTypes.h>
-#include <app/data-model-provider/Provider.h>
-#endif
-
 namespace chip {
 namespace rpc {
 
@@ -217,7 +213,6 @@
         PW_TRY(ChipErrorToPwStatus(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)));
         PW_TRY(ChipErrorToPwStatus(attributeReports.Init(&writer, kReportContextTag)));
 
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
         // TODO: this assumes a singleton data model provider
         app::DataModel::Provider * provider = app::InteractionModelEngine::GetInstance()->GetDataModelProvider();
 
@@ -243,10 +238,6 @@
             return ::pw::Status::Internal();
         }
 
-#else
-        PW_TRY(ChipErrorToPwStatus(app::ReadSingleClusterData(subjectDescriptor, false, path, attributeReports, nullptr)));
-#endif
-
         attributeReports.EndOfContainer();
         PW_TRY(ChipErrorToPwStatus(writer.EndContainer(outer)));
         PW_TRY(ChipErrorToPwStatus(writer.Finalize()));
diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py
index 52696de..ff7dd29 100755
--- a/scripts/build/build/targets.py
+++ b/scripts/build/build/targets.py
@@ -113,8 +113,8 @@
         TargetPart('chip-tool', app=HostApp.CHIP_TOOL),
         TargetPart('thermostat', app=HostApp.THERMOSTAT),
         # TODO: controllers depending on a datamodel is odd. For now fix compile dependencies on ember.
-        TargetPart('java-matter-controller', app=HostApp.JAVA_MATTER_CONTROLLER, data_model_interface="disabled"),
-        TargetPart('kotlin-matter-controller', app=HostApp.KOTLIN_MATTER_CONTROLLER, data_model_interface="disabled"),
+        TargetPart('java-matter-controller', app=HostApp.JAVA_MATTER_CONTROLLER),
+        TargetPart('kotlin-matter-controller', app=HostApp.KOTLIN_MATTER_CONTROLLER),
         TargetPart('minmdns', app=HostApp.MIN_MDNS),
         TargetPart('light', app=HostApp.LIGHT),
         TargetPart('light-data-model-no-unique-id', app=HostApp.LIGHT_DATA_MODEL_NO_UNIQUE_ID),
@@ -196,10 +196,6 @@
     target.AppendModifier('enable-dnssd-tests', enable_dnssd_tests=True).OnlyIfRe('-tests')
     target.AppendModifier('disable-dnssd-tests', enable_dnssd_tests=False).OnlyIfRe('-tests')
     target.AppendModifier('chip-casting-simplified', chip_casting_simplified=True).OnlyIfRe('-tv-casting-app')
-    target.AppendModifier('data-model-check', data_model_interface="check").ExceptIfRe('-data-model-(enabled|disabled)')
-    target.AppendModifier('data-model-disabled', data_model_interface="disabled").ExceptIfRe('-data-model-(check|enabled)')
-    target.AppendModifier('data-model-enabled', data_model_interface="enabled").ExceptIfRe('-data-model-(check|disabled)')
-    target.AppendModifier('check-failure-die', chip_data_model_check_die_on_failure=True).OnlyIfRe('-data-model-check')
     target.AppendModifier('googletest', use_googletest=True).OnlyIfRe('-tests')
 
     return target
@@ -236,8 +232,6 @@
     target.AppendModifier('rpc', enable_rpcs=True)
     target.AppendModifier('ipv6only', enable_ipv4=False)
     target.AppendModifier('tracing', enable_insights_trace=True).OnlyIfRe("light")
-    target.AppendModifier('data-model-disabled', data_model_interface="disabled").ExceptIfRe('-data-model-enabled')
-    target.AppendModifier('data-model-enabled', data_model_interface="enabled").ExceptIfRe('-data-model-disabled')
 
     return target
 
@@ -339,8 +333,6 @@
     ])
 
     target.AppendModifier('rpc', enable_rpcs=True)
-    target.AppendModifier('data-model-disabled', use_data_model_interface=False).ExceptIfRe('-data-model-enabled')
-    target.AppendModifier('data-model-enabled', use_data_model_interface=True).ExceptIfRe('-data-model-disabled')
 
     return target
 
@@ -426,8 +418,6 @@
         '-(release|debug)')
     target.AppendModifier('debug', profile=MbedProfile.DEBUG).ExceptIfRe(
         '-(release|develop)')
-    target.AppendModifier('data-model-disabled', data_model_interface="disabled").ExceptIfRe('-data-model-enabled')
-    target.AppendModifier('data-model-enabled', data_model_interface="enabled").ExceptIfRe('-data-model-disabled')
 
     return target
 
@@ -556,8 +546,6 @@
     target.AppendModifier(name="ethernet", enable_ethernet=True).OnlyIfRe('rw61x_eth-zephyr')
     target.AppendModifier(name="thread", enable_thread=True).ExceptIfRe('zephyr')
     target.AppendModifier(name="matter-shell", enable_shell=True).ExceptIfRe('k32w0|k32w1')
-    target.AppendModifier('data-model-disabled', data_model_interface="disabled").ExceptIfRe('-data-model-enabled')
-    target.AppendModifier('data-model-enabled', data_model_interface="enabled").ExceptIfRe('-data-model-disabled')
     target.AppendModifier(name="factory-build", enable_factory_data_build=True).OnlyIfRe('rt1060|rt1170|rw61x')
     target.AppendModifier(name="frdm", board_variant=NxpBoardVariant.FRDM).OnlyIfRe('rw61x')
     target.AppendModifier(name="cmake", build_system=NxpBuildSystem.CMAKE).OnlyIfRe('rw61x')
@@ -649,8 +637,6 @@
     ])
 
     target.AppendModifier('updateimage', update_image=True)
-    target.AppendModifier('data-model-disabled', data_model_interface="disabled").ExceptIfRe('-data-model-enabled')
-    target.AppendModifier('data-model-enabled', data_model_interface="enabled").ExceptIfRe('-data-model-disabled')
 
     return target
 
@@ -814,8 +800,6 @@
     target.AppendModifier('4mb', enable_4mb_flash=True)
     target.AppendModifier('mars', mars_board_config=True)
     target.AppendModifier('usb', usb_board_config=True)
-    target.AppendModifier('data-model-disabled', use_data_model_interface=False).ExceptIfRe('-data-model-enabled')
-    target.AppendModifier('data-model-enabled', use_data_model_interface=True).ExceptIfRe('-data-model-disabled')
 
     return target
 
diff --git a/scripts/build/builders/esp32.py b/scripts/build/builders/esp32.py
index a225315..02f7e25 100644
--- a/scripts/build/builders/esp32.py
+++ b/scripts/build/builders/esp32.py
@@ -155,7 +155,6 @@
                  enable_rpcs: bool = False,
                  enable_ipv4: bool = True,
                  enable_insights_trace: bool = False,
-                 data_model_interface: Optional[str] = None,
                  ):
         super(Esp32Builder, self).__init__(root, runner)
         self.board = board
@@ -163,7 +162,6 @@
         self.enable_rpcs = enable_rpcs
         self.enable_ipv4 = enable_ipv4
         self.enable_insights_trace = enable_insights_trace
-        self.data_model_interface = data_model_interface
 
         if not app.IsCompatible(board):
             raise Exception(
@@ -218,9 +216,6 @@
             cmake_flags.append(
                 f"-DCHIP_CODEGEN_PREGEN_DIR={shlex.quote(self.options.pregen_dir)}")
 
-        if self.data_model_interface:
-            cmake_flags.append(f'-DCHIP_DATA_MODEL_INTERFACE={self.data_model_interface}')
-
         cmake_args = ['-C', self.ExamplePath, '-B',
                       shlex.quote(self.output_dir)] + cmake_flags
 
diff --git a/scripts/build/builders/host.py b/scripts/build/builders/host.py
index dbb85f9..0ced127 100644
--- a/scripts/build/builders/host.py
+++ b/scripts/build/builders/host.py
@@ -334,8 +334,6 @@
                  enable_test_event_triggers=None,
                  enable_dnssd_tests: Optional[bool] = None,
                  chip_casting_simplified: Optional[bool] = None,
-                 data_model_interface: Optional[str] = None,
-                 chip_data_model_check_die_on_failure: Optional[bool] = None,
                  disable_shell=False,
                  use_googletest=False,
                  ):
@@ -375,9 +373,6 @@
         if use_ubsan:
             self.extra_gn_options.append('is_ubsan=true')
 
-        if data_model_interface is not None:
-            self.extra_gn_options.append(f'chip_use_data_model_interface="{data_model_interface}"')
-
         if use_dmalloc:
             self.extra_gn_options.append('chip_config_memory_debug_checks=true')
             self.extra_gn_options.append('chip_config_memory_debug_dmalloc=true')
@@ -437,13 +432,7 @@
 
         if app == HostApp.TESTS:
             self.extra_gn_options.append('chip_build_tests=true')
-            self.extra_gn_options.append('chip_data_model_check_die_on_failure=true')
             self.build_command = 'check'
-        elif chip_data_model_check_die_on_failure is not None:
-            if chip_data_model_check_die_on_failure:
-                self.extra_gn_options.append('chip_data_model_check_die_on_failure=true')
-            else:
-                self.extra_gn_options.append('chip_data_model_check_die_on_failure=false')
 
         if app == HostApp.EFR32_TEST_RUNNER:
             self.build_command = 'runner'
diff --git a/scripts/build/builders/mbed.py b/scripts/build/builders/mbed.py
index cc4eb83..92ae4e3 100644
--- a/scripts/build/builders/mbed.py
+++ b/scripts/build/builders/mbed.py
@@ -103,7 +103,6 @@
                  app: MbedApp = MbedApp.LOCK,
                  board: MbedBoard = MbedBoard.CY8CPROTO_062_4343W,
                  profile: MbedProfile = MbedProfile.RELEASE,
-                 data_model_interface: Optional[str] = None,
                  ):
         super(MbedBuilder, self).__init__(root, runner)
         self.app = app
@@ -114,7 +113,6 @@
             self.root, 'third_party', 'mbed-os', 'repo')
         self.mbed_os_posix_socket_path = os.path.join(
             self.root, 'third_party', 'mbed-os-posix-socket', 'repo')
-        self.data_model_interface = data_model_interface
 
     @property
     def ExamplePath(self):
@@ -135,9 +133,6 @@
             flags.append(f"-DMBED_OS_PATH={shlex.quote(self.mbed_os_path)}")
             flags.append(f"-DMBED_OS_POSIX_SOCKET_PATH={shlex.quote(self.mbed_os_posix_socket_path)}")
 
-            if self.data_model_interface is not None:
-                flags.append(f"-DCHIP_DATA_MODEL_INTERFACE={self.data_model_interface}")
-
             if self.options.pregen_dir:
                 flags.append(f"-DCHIP_CODEGEN_PREGEN_DIR={shlex.quote(self.options.pregen_dir)}")
 
diff --git a/scripts/build/builders/nrf.py b/scripts/build/builders/nrf.py
index b94a695..bd681ab 100644
--- a/scripts/build/builders/nrf.py
+++ b/scripts/build/builders/nrf.py
@@ -141,13 +141,11 @@
                  app: NrfApp = NrfApp.LIGHT,
                  board: NrfBoard = NrfBoard.NRF52840DK,
                  enable_rpcs: bool = False,
-                 use_data_model_interface: Optional[bool] = None,
                  ):
         super(NrfConnectBuilder, self).__init__(root, runner)
         self.app = app
         self.board = board
         self.enable_rpcs = enable_rpcs
-        self.use_data_model_interface = use_data_model_interface
 
     def generate(self):
         if not os.path.exists(self.output_dir):
@@ -191,10 +189,6 @@
             if self.options.pregen_dir:
                 flags.append(f"-DCHIP_CODEGEN_PREGEN_DIR={shlex.quote(self.options.pregen_dir)}")
 
-            if self.use_data_model_interface is not None:
-                value = 'y' if self.use_data_model_interface else 'n'
-                flags.append(f"-DCONFIG_USE_CHIP_DATA_MODEL_INTERFACE={value}")
-
             build_flags = " -- " + " ".join(flags) if len(flags) > 0 else ""
 
             cmd = 'source "$ZEPHYR_BASE/zephyr-env.sh";\nexport ZEPHYR_TOOLCHAIN_VARIANT=zephyr;'
diff --git a/scripts/build/builders/nxp.py b/scripts/build/builders/nxp.py
index 0f9ebed..fa24ef2 100644
--- a/scripts/build/builders/nxp.py
+++ b/scripts/build/builders/nxp.py
@@ -190,7 +190,6 @@
                  enable_ethernet: bool = False,
                  enable_shell: bool = False,
                  enable_ota: bool = False,
-                 data_model_interface: Optional[str] = None,
                  enable_factory_data_build: bool = False,
                  disable_pairing_autostart: bool = False,
                  iw416_transceiver: bool = False,
@@ -220,7 +219,6 @@
         self.enable_ethernet = enable_ethernet
         self.enable_ota = enable_ota
         self.enable_shell = enable_shell
-        self.data_model_interface = data_model_interface
         self.enable_factory_data_build = enable_factory_data_build
         self.disable_pairing_autostart = disable_pairing_autostart
         self.board_variant = board_variant
@@ -309,9 +307,6 @@
             if self.board == NxpBoard.RT1170:
                 args.append('chip_enable_openthread=true chip_inet_config_enable_ipv4=false')
 
-        if self.data_model_interface is not None:
-            args.append(f'chip_use_data_model_interface="{self.data_model_interface}"')
-
         if self.board_variant:
             if self.board == NxpBoard.RT1060:
                 flag_board_variant = "evkname=\\\"%s\\\"" % self.board_variant.BoardVariantName(self.board)
@@ -349,11 +344,6 @@
             flags.append("-DCONFIG_CHIP_DEVICE_SOFTWARE_VERSION=2")
             flags.append("-DCONFIG_CHIP_DEVICE_SOFTWARE_VERSION_STRING=\"2.0\"")
 
-        if self.data_model_interface:
-            # NOTE: this is not supporting "check"
-            enabled = "y" if self.data_model_interface.lower() == "enabled" else "n"
-            flags.append(f"-DCONFIG_USE_CHIP_DATA_MODEL_INTERFACE={enabled}")
-
         if self.enable_ota:
             flags.append("-DCONFIG_CHIP_OTA_REQUESTOR=true")
             if self.os_env == NxpOsUsed.FREERTOS and self.board == NxpBoard.RW61X:
diff --git a/scripts/build/builders/qpg.py b/scripts/build/builders/qpg.py
index 93feaee..2de1d10 100644
--- a/scripts/build/builders/qpg.py
+++ b/scripts/build/builders/qpg.py
@@ -110,7 +110,6 @@
                  flavour: QpgFlavour = QpgFlavour.EXT_FLASH,
                  enable_rpcs: bool = False,
                  update_image: bool = False,
-                 data_model_interface: Optional[str] = None,
                  ):
         super(QpgBuilder, self).__init__(
             root=app.BuildRoot(root),
@@ -120,7 +119,6 @@
         self.flavour = flavour
         self.enable_rpcs = enable_rpcs
         self.update_image = update_image
-        self.data_model_interface = data_model_interface
 
     def GnBuildArgs(self):
         args = ['qpg_target_ic=\"%s\" qpg_flavour=\"%s\"' % (self.board.GnArgName(), self.flavour.GnFlavourName())]
@@ -128,8 +126,6 @@
             args.append('import("//with_pw_rpc.gni")')
         if self.update_image:
             args.append('matter_ota_test_image=true')
-        if self.data_model_interface:
-            args.append(f'chip_use_data_model_interface="{self.data_model_interface}"')
         return args
 
     def build_outputs(self):
diff --git a/scripts/build/builders/telink.py b/scripts/build/builders/telink.py
index 2badbce..1145b84 100644
--- a/scripts/build/builders/telink.py
+++ b/scripts/build/builders/telink.py
@@ -154,7 +154,6 @@
                  enable_4mb_flash: bool = False,
                  mars_board_config: bool = False,
                  usb_board_config: bool = False,
-                 use_data_model_interface: Optional[str] = None,
                  ):
         super(TelinkBuilder, self).__init__(root, runner)
         self.app = app
@@ -167,7 +166,6 @@
         self.enable_4mb_flash = enable_4mb_flash
         self.mars_board_config = mars_board_config
         self.usb_board_config = usb_board_config
-        self.use_data_model_interface = use_data_model_interface
 
     def get_cmd_prefixes(self):
         if not self._runner.dry_run:
@@ -215,10 +213,6 @@
         if self.options.pregen_dir:
             flags.append(f"-DCHIP_CODEGEN_PREGEN_DIR={shlex.quote(self.options.pregen_dir)}")
 
-        if self.use_data_model_interface is not None:
-            value = 'y' if self.use_data_model_interface else 'n'
-            flags.append(f"-DCONFIG_USE_CHIP_DATA_MODEL_INTERFACE={value}")
-
         build_flags = " -- " + " ".join(flags) if len(flags) > 0 else ""
 
         cmd = self.get_cmd_prefixes()
diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt
index 5e17f58..e585494 100644
--- a/scripts/build/testdata/all_targets_linux_x64.txt
+++ b/scripts/build/testdata/all_targets_linux_x64.txt
@@ -6,21 +6,21 @@
 ti-cc13x4_26x4-{lighting,lock,pump,pump-controller}[-mtd][-ftd]
 cyw30739-{cyw30739b2_p5_evk_01,cyw30739b2_p5_evk_02,cyw30739b2_p5_evk_03,cyw930739m2evb_01,cyw930739m2evb_02}-{light,light-switch,lock,thermostat}
 efr32-{brd2704b,brd4316a,brd4317a,brd4318a,brd4319a,brd4186a,brd4187a,brd2601b,brd4187c,brd4186c,brd2703a,brd4338a,brd2605a,brd4343a}-{window-covering,switch,unit-test,light,lock,thermostat,pump,air-quality-sensor-app}[-rpc][-with-ota-requestor][-icd][-low-power][-shell][-no-logging][-openthread-mtd][-heap-monitoring][-no-openthread-cli][-show-qr-code][-wifi][-rs9116][-wf200][-siwx917][-ipv4][-additional-data-advertising][-use-ot-lib][-use-ot-coap-lib][-no-version][-skip-rps-generation]
-esp32-{m5stack,c3devkit,devkitc,qemu}-{all-clusters,all-clusters-minimal,energy-management,ota-provider,ota-requestor,shell,light,lock,bridge,temperature-measurement,ota-requestor,tests}[-rpc][-ipv6only][-tracing][-data-model-disabled][-data-model-enabled]
+esp32-{m5stack,c3devkit,devkitc,qemu}-{all-clusters,all-clusters-minimal,energy-management,ota-provider,ota-requestor,shell,light,lock,bridge,temperature-measurement,ota-requestor,tests}[-rpc][-ipv6only][-tracing]
 genio-lighting-app
 linux-fake-tests[-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-pw-fuzztest][-coverage][-dmalloc][-clang]
-linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,thermostat,java-matter-controller,kotlin-matter-controller,minmdns,light,light-data-model-no-unique-id,lock,shell,ota-provider,ota-requestor,simulated-app1,simulated-app2,python-bindings,tv-app,tv-casting-app,bridge,fabric-admin,fabric-bridge,fabric-sync,tests,chip-cert,address-resolve-tool,contact-sensor,dishwasher,microwave-oven,refrigerator,rvc,air-purifier,lit-icd,air-quality-sensor,network-manager,energy-management,water-leak-detector}[-nodeps][-nlfaultinject][-platform-mdns][-minmdns-verbose][-libnl][-same-event-loop][-no-interactive][-ipv6only][-no-ble][-no-wifi][-no-thread][-no-shell][-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-pw-fuzztest][-coverage][-dmalloc][-clang][-test][-rpc][-with-ui][-evse-test-event][-enable-dnssd-tests][-disable-dnssd-tests][-chip-casting-simplified][-data-model-check][-data-model-disabled][-data-model-enabled][-check-failure-die][-googletest]
+linux-{x64,arm64}-{rpc-console,all-clusters,all-clusters-minimal,chip-tool,thermostat,java-matter-controller,kotlin-matter-controller,minmdns,light,light-data-model-no-unique-id,lock,shell,ota-provider,ota-requestor,simulated-app1,simulated-app2,python-bindings,tv-app,tv-casting-app,bridge,fabric-admin,fabric-bridge,fabric-sync,tests,chip-cert,address-resolve-tool,contact-sensor,dishwasher,microwave-oven,refrigerator,rvc,air-purifier,lit-icd,air-quality-sensor,network-manager,energy-management,water-leak-detector}[-nodeps][-nlfaultinject][-platform-mdns][-minmdns-verbose][-libnl][-same-event-loop][-no-interactive][-ipv6only][-no-ble][-no-wifi][-no-thread][-no-shell][-mbedtls][-boringssl][-asan][-tsan][-ubsan][-libfuzzer][-ossfuzz][-pw-fuzztest][-coverage][-dmalloc][-clang][-test][-rpc][-with-ui][-evse-test-event][-enable-dnssd-tests][-disable-dnssd-tests][-chip-casting-simplified][-googletest]
 linux-x64-efr32-test-runner[-clang]
 imx-{chip-tool,lighting-app,thermostat,all-clusters-app,all-clusters-minimal-app,ota-provider-app}[-release]
 infineon-psoc6-{lock,light,all-clusters,all-clusters-minimal}[-ota][-updateimage][-trustm]
-nxp-{k32w0,k32w1,rt1060,rt1170,rw61x,rw61x_eth,mcxw71}-{zephyr,freertos}-{lighting,contact-sensor,lock-app,all-clusters,laundry-washer,thermostat}[-factory][-low-power][-lit][-fro32k][-smu2][-dac-conversion][-rotating-id][-sw-v2][-ota][-wifi][-ethernet][-thread][-matter-shell][-data-model-disabled][-data-model-enabled][-factory-build][-frdm][-cmake][-evkc][-iw416][-w8801][-iwx12][-log-all][-log-progress][-log-error][-log-none]
-mbed-cy8cproto_062_4343w-{lock,light,all-clusters,all-clusters-minimal,pigweed,ota-requestor,shell}[-release][-develop][-debug][-data-model-disabled][-data-model-enabled]
+nxp-{k32w0,k32w1,rt1060,rt1170,rw61x,rw61x_eth,mcxw71}-{zephyr,freertos}-{lighting,contact-sensor,lock-app,all-clusters,laundry-washer,thermostat}[-factory][-low-power][-lit][-fro32k][-smu2][-dac-conversion][-rotating-id][-sw-v2][-ota][-wifi][-ethernet][-thread][-matter-shell][-factory-build][-frdm][-cmake][-evkc][-iw416][-w8801][-iwx12][-log-all][-log-progress][-log-error][-log-none]
+mbed-cy8cproto_062_4343w-{lock,light,all-clusters,all-clusters-minimal,pigweed,ota-requestor,shell}[-release][-develop][-debug]
 mw320-all-clusters-app
-nrf-{nrf5340dk,nrf52840dk,nrf52840dongle}-{all-clusters,all-clusters-minimal,lock,light,light-switch,shell,pump,pump-controller,window-covering}[-rpc][-data-model-disabled][-data-model-enabled]
+nrf-{nrf5340dk,nrf52840dk,nrf52840dongle}-{all-clusters,all-clusters-minimal,lock,light,light-switch,shell,pump,pump-controller,window-covering}[-rpc]
 nrf-native-posix-64-tests
 nuttx-x64-light
-qpg-qpg6105-{lock,light,shell,persistent-storage,light-switch,thermostat}[-updateimage][-data-model-disabled][-data-model-enabled]
+qpg-qpg6105-{lock,light,shell,persistent-storage,light-switch,thermostat}[-updateimage]
 stm32-stm32wb5mm-dk-light
 tizen-arm-{all-clusters,chip-tool,light,tests}[-no-ble][-no-thread][-no-wifi][-asan][-ubsan][-coverage][-with-ui]
-telink-{tlsr9118bdk40d,tlsr9518adk80d,tlsr9528a,tlsr9528a_retention,tlsr9258a,tlsr9258a_retention}-{air-quality-sensor,all-clusters,all-clusters-minimal,bridge,contact-sensor,light,light-switch,lock,ota-requestor,pump,pump-controller,shell,smoke-co-alarm,temperature-measurement,thermostat,window-covering}[-ota][-dfu][-shell][-rpc][-factory-data][-4mb][-mars][-usb][-data-model-disabled][-data-model-enabled]
+telink-{tlsr9118bdk40d,tlsr9518adk80d,tlsr9528a,tlsr9528a_retention,tlsr9258a,tlsr9258a_retention}-{air-quality-sensor,all-clusters,all-clusters-minimal,bridge,contact-sensor,light,light-switch,lock,ota-requestor,pump,pump-controller,shell,smoke-co-alarm,temperature-measurement,thermostat,window-covering}[-ota][-dfu][-shell][-rpc][-factory-data][-4mb][-mars][-usb]
 openiotsdk-{shell,lock}[-mbedtls][-psa]
diff --git a/scripts/tests/local.py b/scripts/tests/local.py
index f44bdc2..aaa4d88 100755
--- a/scripts/tests/local.py
+++ b/scripts/tests/local.py
@@ -587,11 +587,8 @@
 
 
 @cli.command()
-@click.option(
-    "--data-model-interface", type=click.Choice(["enabled", "disabled", "check"])
-)
 @click.option("--asan", is_flag=True, default=False, show_default=True)
-def build_casting_apps(data_model_interface, asan):
+def build_casting_apps(asan):
     """
     Builds Applications used for tv casting tests
     """
@@ -603,10 +600,6 @@
     tv_args.append('chip_crypto="boringssl"')
     casting_args.append('chip_crypto="boringssl"')
 
-    if data_model_interface:
-        tv_args.append(f'chip_use_data_model_interface="{data_model_interface}"')
-        casting_args.append(f'chip_use_data_model_interface="{data_model_interface}"')
-
     if asan:
         tv_args.append("is_asan=true is_clang=true")
         casting_args.append("is_asan=true is_clang=true")
diff --git a/src/app/AttributePathExpandIterator-Checked.cpp b/src/app/AttributePathExpandIterator-Checked.cpp
deleted file mode 100644
index 119eb29..0000000
--- a/src/app/AttributePathExpandIterator-Checked.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- *    Copyright (c) 2024 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#include "lib/support/logging/TextOnlyLogging.h"
-#include <app/AttributePathExpandIterator-Checked.h>
-
-namespace chip {
-namespace app {
-AttributePathExpandIteratorChecked::AttributePathExpandIteratorChecked(DataModel::Provider * dataModel,
-                                                                       SingleLinkedListNode<AttributePathParams> * attributePath) :
-    mDataModelIterator(dataModel, attributePath),
-    mEmberIterator(dataModel, attributePath)
-{
-    CheckOutputsIdentical("Constructor");
-}
-
-bool AttributePathExpandIteratorChecked::Next()
-{
-    bool dmResult = mDataModelIterator.Next();
-    bool emResult = mEmberIterator.Next();
-
-    CheckOutputsIdentical("Next");
-
-    VerifyOrDie(dmResult == emResult);
-
-    return emResult;
-}
-
-bool AttributePathExpandIteratorChecked::Get(ConcreteAttributePath & aPath)
-{
-    CheckOutputsIdentical("Get");
-    return mEmberIterator.Get(aPath);
-}
-
-void AttributePathExpandIteratorChecked::ResetCurrentCluster()
-{
-    mDataModelIterator.ResetCurrentCluster();
-    mEmberIterator.ResetCurrentCluster();
-
-    CheckOutputsIdentical("ResetCurrentCluster");
-}
-
-void AttributePathExpandIteratorChecked::ResetTo(SingleLinkedListNode<AttributePathParams> * paths)
-
-{
-    mDataModelIterator.ResetTo(paths);
-    mEmberIterator.ResetTo(paths);
-    CheckOutputsIdentical("ResetTo");
-}
-
-void AttributePathExpandIteratorChecked::CheckOutputsIdentical(const char * msg)
-{
-    ConcreteAttributePath dmPath;
-    ConcreteAttributePath emPath;
-
-    bool dmResult = mDataModelIterator.Get(dmPath);
-    bool emResult = mEmberIterator.Get(emPath);
-
-    if (dmResult == emResult)
-    {
-        // We check for:
-        //    - either failed result (in which case path should not matter)
-        //    - or exact match of paths on success
-        //
-        // NOTE: extra logic because mExpanded is NOT considered in operator== (ugly...)
-        if ((dmResult == false) || ((dmPath == emPath) && (dmPath.mExpanded == emPath.mExpanded)))
-        {
-            // outputs are identical. All is good
-            return;
-        }
-    }
-
-    ChipLogProgress(Test, "Different paths in DM vs EMBER (%d and %d) in %s", dmResult, emResult, msg);
-    ChipLogProgress(Test, "   DM PATH:    0x%X/" ChipLogFormatMEI "/" ChipLogFormatMEI " (%s)", dmPath.mEndpointId,
-                    ChipLogValueMEI(dmPath.mClusterId), ChipLogValueMEI(dmPath.mAttributeId),
-                    dmPath.mExpanded ? "EXPANDED" : "NOT expanded");
-    ChipLogProgress(Test, "   EMBER PATH: 0x%X/" ChipLogFormatMEI "/" ChipLogFormatMEI " (%s)", emPath.mEndpointId,
-                    ChipLogValueMEI(emPath.mClusterId), ChipLogValueMEI(emPath.mAttributeId),
-                    emPath.mExpanded ? "EXPANDED" : "NOT expanded");
-
-    chipDie();
-}
-
-} // namespace app
-} // namespace chip
diff --git a/src/app/AttributePathExpandIterator-Checked.h b/src/app/AttributePathExpandIterator-Checked.h
deleted file mode 100644
index efbe99e..0000000
--- a/src/app/AttributePathExpandIterator-Checked.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- *    Copyright (c) 2024 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#pragma once
-
-#include <app/AttributePathExpandIterator-DataModel.h>
-#include <app/AttributePathExpandIterator-Ember.h>
-
-namespace chip {
-namespace app {
-
-class AttributePathExpandIteratorChecked
-{
-public:
-    AttributePathExpandIteratorChecked(DataModel::Provider * dataModel, SingleLinkedListNode<AttributePathParams> * attributePath);
-
-    bool Next();
-    bool Get(ConcreteAttributePath & aPath);
-    void ResetCurrentCluster();
-    void ResetTo(SingleLinkedListNode<AttributePathParams> * paths);
-
-private:
-    AttributePathExpandIteratorDataModel mDataModelIterator;
-    AttributePathExpandIteratorEmber mEmberIterator;
-
-    void CheckOutputsIdentical(const char * msg);
-};
-
-} // namespace app
-} // namespace chip
diff --git a/src/app/AttributePathExpandIterator-DataModel.h b/src/app/AttributePathExpandIterator-DataModel.h
deleted file mode 100644
index c8baca7..0000000
--- a/src/app/AttributePathExpandIterator-DataModel.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- *    Copyright (c) 2024 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-#pragma once
-
-#include <app/AttributePathParams.h>
-#include <app/ConcreteAttributePath.h>
-#include <app/data-model-provider/Provider.h>
-#include <lib/support/LinkedList.h>
-
-namespace chip {
-namespace app {
-
-/**
- * AttributePathExpandIteratorDataModel is used to iterate over a linked list of AttributePathParams-s.
- * The AttributePathExpandIteratorDataModel is copiable, however, the given cluster info must be valid when calling Next().
- *
- * AttributePathExpandIteratorDataModel will expand attribute paths with wildcards, and only emit existing paths for
- * AttributePathParams with wildcards. For AttributePathParams with a concrete path (i.e. does not contain wildcards),
- * AttributePathExpandIteratorDataModel will emit them as-is.
- *
- * The typical use of AttributePathExpandIteratorDataModel may look like:
- * ConcreteAttributePath path;
- * for (AttributePathExpandIteratorDataModel iterator(AttributePathParams); iterator.Get(path); iterator.Next()) {...}
- *
- * The iterator does not copy the given AttributePathParams, The given AttributePathParams must be valid when using the iterator.
- * If the set of endpoints, clusters, or attributes that are supported changes, AttributePathExpandIteratorDataModel must be
- * reinitialized.
- *
- * A initialized iterator will return the first valid path, no need to call Next() before calling Get() for the first time.
- *
- * Note: The Next() and Get() are two separate operations by design since a possible call of this iterator might be:
- * - Get()
- * - Chunk full, return
- * - In a new chunk, Get()
- *
- * TODO: The AttributePathParams may support a group id, the iterator should be able to call group data provider to expand the group
- * id.
- */
-class AttributePathExpandIteratorDataModel
-{
-public:
-    AttributePathExpandIteratorDataModel(DataModel::Provider * provider, SingleLinkedListNode<AttributePathParams> * attributePath);
-
-    /**
-     * Proceed the iterator to the next attribute path in the given cluster info.
-     *
-     * Returns false if AttributePathExpandIteratorDataModeDataModel has exhausted all paths in the given AttributePathParams list.
-     */
-    bool Next();
-
-    /**
-     * Fills the aPath with the path the iterator currently points to.
-     * Returns false if the iterator is not pointing to a valid path (i.e. it has exhausted the cluster info).
-     */
-    bool Get(ConcreteAttributePath & aPath)
-    {
-        aPath = mOutputPath;
-        return (mpAttributePath != nullptr);
-    }
-
-    /**
-     * Reset the iterator to the beginning of current cluster if we are in the middle of expanding a wildcard attribute id for some
-     * cluster.
-     *
-     * When attributes are changed in the middle of expanding a wildcard attribute, we need to reset the iterator, to provide the
-     * client with a consistent state of the cluster.
-     */
-    void ResetCurrentCluster();
-
-    /** Start iterating over the given `paths` */
-    inline void ResetTo(SingleLinkedListNode<AttributePathParams> * paths)
-    {
-        *this = AttributePathExpandIteratorDataModel(mDataModelProvider, paths);
-    }
-
-private:
-    DataModel::Provider * mDataModelProvider;
-    SingleLinkedListNode<AttributePathParams> * mpAttributePath;
-    ConcreteAttributePath mOutputPath;
-
-    /// Move to the next endpoint/cluster/attribute triplet that is valid given
-    /// the current mOutputPath and mpAttributePath
-    ///
-    /// returns true if such a next value was found.
-    bool AdvanceOutputPath();
-
-    /// Get the next attribute ID in mOutputPath(endpoint/cluster) if one is available.
-    /// Will start from the beginning if current mOutputPath.mAttributeId is kInvalidAttributeId
-    ///
-    /// Respects path expansion/values in mpAttributePath
-    ///
-    /// Handles Global attributes (which are returned at the end)
-    std::optional<AttributeId> NextAttributeId();
-
-    /// Get the next cluster ID in mOutputPath(endpoint) if one is available.
-    /// Will start from the beginning if current mOutputPath.mClusterId is kInvalidClusterId
-    ///
-    /// Respects path expansion/values in mpAttributePath
-    std::optional<ClusterId> NextClusterId();
-
-    /// Get the next endpoint ID in mOutputPath if one is available.
-    /// Will start from the beginning if current mOutputPath.mEndpointId is kInvalidEndpointId
-    ///
-    /// Respects path expansion/values in mpAttributePath
-    std::optional<ClusterId> NextEndpointId();
-
-    /// Checks if the given attributeId is valid for the current mOutputPath(endpoint/cluster)
-    ///
-    /// Meaning that it is known to the data model OR it is a always-there global attribute.
-    bool IsValidAttributeId(AttributeId attributeId);
-};
-
-} // namespace app
-} // namespace chip
diff --git a/src/app/AttributePathExpandIterator-Ember.cpp b/src/app/AttributePathExpandIterator-Ember.cpp
deleted file mode 100644
index 1149f0c..0000000
--- a/src/app/AttributePathExpandIterator-Ember.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- *
- *    Copyright (c) 2021 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#include <app/AttributePathExpandIterator-Ember.h>
-
-#include <app/AttributePathParams.h>
-#include <app/ConcreteAttributePath.h>
-#include <app/EventManagement.h>
-#include <app/GlobalAttributes.h>
-#include <app/util/att-storage.h>
-#include <app/util/endpoint-config-api.h>
-#include <lib/core/CHIPCore.h>
-#include <lib/core/TLVDebug.h>
-#include <lib/support/CodeUtils.h>
-#include <lib/support/DLLUtil.h>
-#include <lib/support/logging/CHIPLogging.h>
-
-using namespace chip;
-
-// TODO: Need to make it so that declarations of things that don't depend on generated files are not intermixed in af.h with
-// dependencies on generated files, so we don't have to re-declare things here.
-// Note: Some of the generated files that depended by af.h are gen_config.h and gen_tokens.h
-typedef uint8_t EmberAfClusterMask;
-
-extern uint16_t emberAfEndpointCount();
-extern uint16_t emberAfIndexFromEndpoint(EndpointId endpoint);
-extern uint8_t emberAfClusterCount(EndpointId endpoint, bool server);
-extern uint16_t emberAfGetServerAttributeCount(chip::EndpointId endpoint, chip::ClusterId cluster);
-extern uint16_t emberAfGetServerAttributeIndexByAttributeId(chip::EndpointId endpoint, chip::ClusterId cluster,
-                                                            chip::AttributeId attributeId);
-extern chip::EndpointId emberAfEndpointFromIndex(uint16_t index);
-extern Optional<ClusterId> emberAfGetNthClusterId(chip::EndpointId endpoint, uint8_t n, bool server);
-extern Optional<AttributeId> emberAfGetServerAttributeIdByIndex(chip::EndpointId endpoint, chip::ClusterId cluster,
-                                                                uint16_t attributeIndex);
-extern uint8_t emberAfClusterIndex(EndpointId endpoint, ClusterId clusterId, EmberAfClusterMask mask);
-extern bool emberAfEndpointIndexIsEnabled(uint16_t index);
-
-namespace chip {
-namespace app {
-
-AttributePathExpandIteratorEmber::AttributePathExpandIteratorEmber(DataModel::Provider *,
-                                                                   SingleLinkedListNode<AttributePathParams> * aAttributePath) :
-    mpAttributePath(aAttributePath)
-{
-
-    // Reset iterator state
-    mEndpointIndex  = UINT16_MAX;
-    mClusterIndex   = UINT8_MAX;
-    mAttributeIndex = UINT16_MAX;
-
-    static_assert(std::numeric_limits<decltype(mGlobalAttributeIndex)>::max() >= ArraySize(GlobalAttributesNotInMetadata),
-                  "Our index won't be able to hold the value we need to hold.");
-    static_assert(std::is_same<decltype(mGlobalAttributeIndex), uint8_t>::value,
-                  "If this changes audit all uses where we set to UINT8_MAX");
-    mGlobalAttributeIndex = UINT8_MAX;
-
-    // Make the iterator ready to emit the first valid path in the list.
-    Next();
-}
-
-void AttributePathExpandIteratorEmber::PrepareEndpointIndexRange(const AttributePathParams & aAttributePath)
-{
-    if (aAttributePath.HasWildcardEndpointId())
-    {
-        mEndpointIndex    = 0;
-        mEndEndpointIndex = emberAfEndpointCount();
-    }
-    else
-    {
-        mEndpointIndex = emberAfIndexFromEndpoint(aAttributePath.mEndpointId);
-        // If the given cluster id does not exist on the given endpoint, it will return uint16(0xFFFF), then endEndpointIndex
-        // will be 0, means we should iterate a null endpoint set (skip it).
-        mEndEndpointIndex = static_cast<uint16_t>(mEndpointIndex + 1);
-    }
-}
-
-void AttributePathExpandIteratorEmber::PrepareClusterIndexRange(const AttributePathParams & aAttributePath, EndpointId aEndpointId)
-{
-    if (aAttributePath.HasWildcardClusterId())
-    {
-        mClusterIndex    = 0;
-        mEndClusterIndex = emberAfClusterCount(aEndpointId, true /* server */);
-    }
-    else
-    {
-        mClusterIndex = emberAfClusterIndex(aEndpointId, aAttributePath.mClusterId, CLUSTER_MASK_SERVER);
-        // If the given cluster id does not exist on the given endpoint, it will return uint8(0xFF), then endClusterIndex
-        // will be 0, means we should iterate a null cluster set (skip it).
-        mEndClusterIndex = static_cast<uint8_t>(mClusterIndex + 1);
-    }
-}
-
-void AttributePathExpandIteratorEmber::PrepareAttributeIndexRange(const AttributePathParams & aAttributePath,
-                                                                  EndpointId aEndpointId, ClusterId aClusterId)
-{
-    if (aAttributePath.HasWildcardAttributeId())
-    {
-        mAttributeIndex          = 0;
-        mEndAttributeIndex       = emberAfGetServerAttributeCount(aEndpointId, aClusterId);
-        mGlobalAttributeIndex    = 0;
-        mGlobalAttributeEndIndex = ArraySize(GlobalAttributesNotInMetadata);
-    }
-    else
-    {
-        mAttributeIndex = emberAfGetServerAttributeIndexByAttributeId(aEndpointId, aClusterId, aAttributePath.mAttributeId);
-        // If the given attribute id does not exist on the given endpoint, it will return uint16(0xFFFF), then endAttributeIndex
-        // will be 0, means we should iterate a null attribute set (skip it).
-        mEndAttributeIndex = static_cast<uint16_t>(mAttributeIndex + 1);
-        if (mAttributeIndex == UINT16_MAX)
-        {
-            // Check whether this is a non-metadata global attribute.
-            //
-            // Default to the max value, which will correspond (after we add 1
-            // and overflow to 0 for the max index) to us not going through
-            // non-metadata global attributes for this attribute.
-            mGlobalAttributeIndex = UINT8_MAX;
-
-            static_assert(ArraySize(GlobalAttributesNotInMetadata) <= UINT8_MAX, "Iterating over at most 256 array entries");
-
-            const uint8_t arraySize = static_cast<uint8_t>(ArraySize(GlobalAttributesNotInMetadata));
-            for (uint8_t idx = 0; idx < arraySize; ++idx)
-            {
-                if (GlobalAttributesNotInMetadata[idx] == aAttributePath.mAttributeId)
-                {
-                    mGlobalAttributeIndex = idx;
-                    break;
-                }
-            }
-            mGlobalAttributeEndIndex = static_cast<uint8_t>(mGlobalAttributeIndex + 1);
-        }
-        else
-        {
-            mGlobalAttributeIndex    = UINT8_MAX;
-            mGlobalAttributeEndIndex = 0;
-        }
-    }
-}
-
-void AttributePathExpandIteratorEmber::ResetCurrentCluster()
-{
-    // If this is a null iterator, or the attribute id of current cluster info is not a wildcard attribute id, then this function
-    // will do nothing, since we won't be expanding the wildcard attribute ids under a cluster.
-    VerifyOrReturn(mpAttributePath != nullptr && mpAttributePath->mValue.HasWildcardAttributeId());
-
-    // Otherwise, we will reset the index for iterating the attributes, so we report the attributes for this cluster again. This
-    // will ensure that the client sees a coherent view of the cluster from the reports generated by a single (wildcard) attribute
-    // path in the request.
-    //
-    // Note that when Next() returns, we must be in one of the following states:
-    // - This is not a wildcard path
-    // - We just expanded some attribute id field
-    // - We have exhausted all paths
-    // Only the second case will happen here since the above check will fail for 1 and 3, so the following Next() call must result
-    // in a valid path, which is the first attribute id we will emit for the current cluster.
-    mAttributeIndex       = UINT16_MAX;
-    mGlobalAttributeIndex = UINT8_MAX;
-    Next();
-}
-
-bool AttributePathExpandIteratorEmber::Next()
-{
-    for (; mpAttributePath != nullptr; (mpAttributePath = mpAttributePath->mpNext, mEndpointIndex = UINT16_MAX))
-    {
-        mOutputPath.mExpanded = mpAttributePath->mValue.IsWildcardPath();
-
-        if (mEndpointIndex == UINT16_MAX)
-        {
-            // Special case: If this is a concrete path, we just return its value as-is.
-            if (!mpAttributePath->mValue.IsWildcardPath())
-            {
-                mOutputPath.mEndpointId  = mpAttributePath->mValue.mEndpointId;
-                mOutputPath.mClusterId   = mpAttributePath->mValue.mClusterId;
-                mOutputPath.mAttributeId = mpAttributePath->mValue.mAttributeId;
-
-                // Prepare for next iteration
-                mEndpointIndex = mEndEndpointIndex = 0;
-                return true;
-            }
-
-            PrepareEndpointIndexRange(mpAttributePath->mValue);
-            mClusterIndex = UINT8_MAX;
-        }
-
-        for (; mEndpointIndex < mEndEndpointIndex;
-             (mEndpointIndex++, mClusterIndex = UINT8_MAX, mAttributeIndex = UINT16_MAX, mGlobalAttributeIndex = UINT8_MAX))
-        {
-            if (!emberAfEndpointIndexIsEnabled(mEndpointIndex))
-            {
-                // Not an enabled endpoint; skip it.
-                continue;
-            }
-
-            EndpointId endpointId = emberAfEndpointFromIndex(mEndpointIndex);
-
-            if (mClusterIndex == UINT8_MAX)
-            {
-                PrepareClusterIndexRange(mpAttributePath->mValue, endpointId);
-                mAttributeIndex       = UINT16_MAX;
-                mGlobalAttributeIndex = UINT8_MAX;
-            }
-
-            for (; mClusterIndex < mEndClusterIndex;
-                 (mClusterIndex++, mAttributeIndex = UINT16_MAX, mGlobalAttributeIndex = UINT8_MAX))
-            {
-                // emberAfGetNthClusterId must return a valid cluster id here since we have verified the mClusterIndex does
-                // not exceed the mEndClusterIndex.
-                ClusterId clusterId = emberAfGetNthClusterId(endpointId, mClusterIndex, true /* server */).Value();
-                if (mAttributeIndex == UINT16_MAX && mGlobalAttributeIndex == UINT8_MAX)
-                {
-                    PrepareAttributeIndexRange(mpAttributePath->mValue, endpointId, clusterId);
-                }
-
-                if (mAttributeIndex < mEndAttributeIndex)
-                {
-                    // GetServerAttributeIdByIdex must return a valid attribute here since we have verified the mAttributeIndex does
-                    // not exceed the mEndAttributeIndex.
-                    mOutputPath.mAttributeId = emberAfGetServerAttributeIdByIndex(endpointId, clusterId, mAttributeIndex).Value();
-                    mOutputPath.mClusterId   = clusterId;
-                    mOutputPath.mEndpointId  = endpointId;
-                    mAttributeIndex++;
-                    // We found a valid attribute path, now return and increase the attribute index for next iteration.
-                    // Return true will skip the increment of mClusterIndex, mEndpointIndex and mpAttributePath.
-                    return true;
-                }
-                if (mGlobalAttributeIndex < mGlobalAttributeEndIndex)
-                {
-                    // Return a path pointing to the next global attribute.
-                    mOutputPath.mAttributeId = GlobalAttributesNotInMetadata[mGlobalAttributeIndex];
-                    mOutputPath.mClusterId   = clusterId;
-                    mOutputPath.mEndpointId  = endpointId;
-                    mGlobalAttributeIndex++;
-                    return true;
-                }
-                // We have exhausted all attributes of this cluster, continue iterating over attributes of next cluster.
-            }
-            // We have exhausted all clusters of this endpoint, continue iterating over clusters of next endpoint.
-        }
-        // We have exhausted all endpoints in this cluster info, continue iterating over next cluster info item.
-    }
-
-    // Reset to default, invalid value.
-    mOutputPath = ConcreteReadAttributePath();
-    return false;
-}
-} // namespace app
-} // namespace chip
diff --git a/src/app/AttributePathExpandIterator-Ember.h b/src/app/AttributePathExpandIterator-Ember.h
deleted file mode 100644
index c7c112d..0000000
--- a/src/app/AttributePathExpandIterator-Ember.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- *
- *    Copyright (c) 2021 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-/**
- * @file
- *   Defines an iterator for iterating all possible paths from a list of AttributePathParams-s according to spec section 8.9.2.2
- * (Valid Attribute Paths)
- */
-
-#pragma once
-
-#include <app/AttributePathParams.h>
-#include <app/ConcreteAttributePath.h>
-#include <app/EventManagement.h>
-#include <app/data-model-provider/Provider.h>
-#include <lib/core/CHIPCore.h>
-#include <lib/support/CodeUtils.h>
-#include <lib/support/DLLUtil.h>
-#include <lib/support/LinkedList.h>
-#include <lib/support/logging/CHIPLogging.h>
-#include <messaging/ExchangeContext.h>
-#include <messaging/ExchangeMgr.h>
-#include <messaging/Flags.h>
-#include <protocols/Protocols.h>
-
-namespace chip {
-namespace app {
-
-/**
- * AttributePathExpandIteratorEmber is used to iterate over a linked list of AttributePathParams-s.
- * The AttributePathExpandIteratorEmber is copiable, however, the given cluster info must be valid when calling Next().
- *
- * AttributePathExpandIteratorEmber will expand attribute paths with wildcards, and only emit existing paths for AttributePathParams
- * with wildcards. For AttributePathParams with a concrete path (i.e. does not contain wildcards), AttributePathExpandIteratorEmber
- * will emit them as-is.
- *
- * The typical use of AttributePathExpandIteratorEmber may look like:
- * ConcreteAttributePath path;
- * for (AttributePathExpandIteratorEmber iterator(AttributePathParams); iterator.Get(path); iterator.Next()) {...}
- *
- * The iterator does not copy the given AttributePathParams, The given AttributePathParams must be valid when using the iterator.
- * If the set of endpoints, clusters, or attributes that are supported changes, AttributePathExpandIteratorEmber must be
- * reinitialized.
- *
- * A initialized iterator will return the first valid path, no need to call Next() before calling Get() for the first time.
- *
- * Note: The Next() and Get() are two separate operations by design since a possible call of this iterator might be:
- * - Get()
- * - Chunk full, return
- * - In a new chunk, Get()
- *
- * TODO: The AttributePathParams may support a group id, the iterator should be able to call group data provider to expand the group
- * id.
- */
-class AttributePathExpandIteratorEmber
-{
-public:
-    AttributePathExpandIteratorEmber(DataModel::Provider *, // datamodel is NOT used by this class
-                                     SingleLinkedListNode<AttributePathParams> * aAttributePath);
-
-    /**
-     * Proceed the iterator to the next attribute path in the given cluster info.
-     *
-     * Returns false if AttributePathExpandIteratorEmber has exhausted all paths in the given AttributePathParams list.
-     */
-    bool Next();
-
-    /**
-     * Fills the aPath with the path the iterator currently points to.
-     * Returns false if the iterator is not pointing to a valid path (i.e. it has exhausted the cluster info).
-     */
-    bool Get(ConcreteAttributePath & aPath)
-    {
-        aPath = mOutputPath;
-        return (mpAttributePath != nullptr); // still handling some path
-    }
-
-    /**
-     * Reset the iterator to the beginning of current cluster if we are in the middle of expanding a wildcard attribute id for some
-     * cluster.
-     *
-     * When attributes are changed in the middle of expanding a wildcard attribute, we need to reset the iterator, to provide the
-     * client with a consistent state of the cluster.
-     */
-    void ResetCurrentCluster();
-
-    /** Start iterating over the given `paths` */
-    inline void ResetTo(SingleLinkedListNode<AttributePathParams> * paths)
-    {
-        *this = AttributePathExpandIteratorEmber(nullptr /* data model is not used */, paths);
-    }
-
-private:
-    SingleLinkedListNode<AttributePathParams> * mpAttributePath;
-
-    ConcreteAttributePath mOutputPath;
-
-    uint16_t mEndpointIndex, mEndEndpointIndex;
-    uint16_t mAttributeIndex, mEndAttributeIndex;
-
-    // Note: should use decltype(EmberAfEndpointType::clusterCount) here, but af-types is including app specific generated files.
-    uint8_t mClusterIndex, mEndClusterIndex;
-    // For dealing with global attributes that are not part of the attribute
-    // metadata.
-    uint8_t mGlobalAttributeIndex, mGlobalAttributeEndIndex;
-
-    /**
-     * Prepare*IndexRange will update mBegin*Index and mEnd*Index variables.
-     * If AttributePathParams contains a wildcard field, it will set mBegin*Index to 0 and mEnd*Index to count.
-     * Or it will set mBegin*Index to the index of the Endpoint/Cluster/Attribute, and mEnd*Index to mBegin*Index + 1.
-     *
-     * If the Endpoint/Cluster/Attribute does not exist, mBegin*Index will be UINT*_MAX, and mEnd*Inde will be 0.
-     *
-     * The index can be used with emberAfEndpointFromIndex, emberAfGetNthClusterId and emberAfGetServerAttributeIdByIndex.
-     */
-    void PrepareEndpointIndexRange(const AttributePathParams & aAttributePath);
-    void PrepareClusterIndexRange(const AttributePathParams & aAttributePath, EndpointId aEndpointId);
-    void PrepareAttributeIndexRange(const AttributePathParams & aAttributePath, EndpointId aEndpointId, ClusterId aClusterId);
-};
-} // namespace app
-} // namespace chip
diff --git a/src/app/AttributePathExpandIterator-DataModel.cpp b/src/app/AttributePathExpandIterator.cpp
similarity index 90%
rename from src/app/AttributePathExpandIterator-DataModel.cpp
rename to src/app/AttributePathExpandIterator.cpp
index 1564db3..96aa277 100644
--- a/src/app/AttributePathExpandIterator-DataModel.cpp
+++ b/src/app/AttributePathExpandIterator.cpp
@@ -14,17 +14,18 @@
  *    See the License for the specific language governing permissions and
  *    limitations under the License.
  */
-#include "lib/support/CodeUtils.h"
-#include <app/AttributePathExpandIterator-DataModel.h>
+#include <app/AttributePathExpandIterator.h>
+
 #include <app/GlobalAttributes.h>
+#include <lib/support/CodeUtils.h>
 
 using namespace chip::app::DataModel;
 
 namespace chip {
 namespace app {
 
-AttributePathExpandIteratorDataModel::AttributePathExpandIteratorDataModel(
-    DataModel::Provider * provider, SingleLinkedListNode<AttributePathParams> * attributePath) :
+AttributePathExpandIterator::AttributePathExpandIterator(DataModel::Provider * provider,
+                                                         SingleLinkedListNode<AttributePathParams> * attributePath) :
     mDataModelProvider(provider),
     mpAttributePath(attributePath), mOutputPath(kInvalidEndpointId, kInvalidClusterId, kInvalidAttributeId)
 
@@ -36,7 +37,7 @@
     Next();
 }
 
-bool AttributePathExpandIteratorDataModel::IsValidAttributeId(AttributeId attributeId)
+bool AttributePathExpandIterator::IsValidAttributeId(AttributeId attributeId)
 {
     switch (attributeId)
     {
@@ -52,7 +53,7 @@
     return mDataModelProvider->GetAttributeInfo(attributePath).has_value();
 }
 
-std::optional<AttributeId> AttributePathExpandIteratorDataModel::NextAttributeId()
+std::optional<AttributeId> AttributePathExpandIterator::NextAttributeId()
 {
     if (mOutputPath.mAttributeId == kInvalidAttributeId)
     {
@@ -107,7 +108,7 @@
     return GlobalAttributesNotInMetadata[0];
 }
 
-std::optional<ClusterId> AttributePathExpandIteratorDataModel::NextClusterId()
+std::optional<ClusterId> AttributePathExpandIterator::NextClusterId()
 {
 
     if (mOutputPath.mClusterId == kInvalidClusterId)
@@ -134,7 +135,7 @@
     return entry.IsValid() ? std::make_optional(entry.path.mClusterId) : std::nullopt;
 }
 
-std::optional<ClusterId> AttributePathExpandIteratorDataModel::NextEndpointId()
+std::optional<ClusterId> AttributePathExpandIterator::NextEndpointId()
 {
     if (mOutputPath.mEndpointId == kInvalidEndpointId)
     {
@@ -153,7 +154,7 @@
     return (id != kInvalidEndpointId) ? std::make_optional(id) : std::nullopt;
 }
 
-void AttributePathExpandIteratorDataModel::ResetCurrentCluster()
+void AttributePathExpandIterator::ResetCurrentCluster()
 {
     // If this is a null iterator, or the attribute id of current cluster info is not a wildcard attribute id, then this function
     // will do nothing, since we won't be expanding the wildcard attribute ids under a cluster.
@@ -165,7 +166,7 @@
     Next();
 }
 
-bool AttributePathExpandIteratorDataModel::AdvanceOutputPath()
+bool AttributePathExpandIterator::AdvanceOutputPath()
 {
     if (!mpAttributePath->mValue.IsWildcardPath())
     {
@@ -218,7 +219,7 @@
     }
 }
 
-bool AttributePathExpandIteratorDataModel::Next()
+bool AttributePathExpandIterator::Next()
 {
     while (mpAttributePath != nullptr)
     {
diff --git a/src/app/AttributePathExpandIterator.h b/src/app/AttributePathExpandIterator.h
index fae69fe..351520f 100644
--- a/src/app/AttributePathExpandIterator.h
+++ b/src/app/AttributePathExpandIterator.h
@@ -17,30 +17,113 @@
  */
 #pragma once
 
-#include <app/AppConfig.h>
-
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL && CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-#include <app/AttributePathExpandIterator-Checked.h>
-#else
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-#include <app/AttributePathExpandIterator-DataModel.h>
-#else
-#include <app/AttributePathExpandIterator-Ember.h>
-#endif // CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-#endif // CHIP_CONFIG_USE_EMBER_DATA_MODEL && CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
+#include <app/AttributePathParams.h>
+#include <app/ConcreteAttributePath.h>
+#include <app/data-model-provider/Provider.h>
+#include <lib/support/LinkedList.h>
 
 namespace chip {
 namespace app {
 
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL && CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-using AttributePathExpandIterator = ::chip::app::AttributePathExpandIteratorChecked;
-#else
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-using AttributePathExpandIterator = ::chip::app::AttributePathExpandIteratorDataModel;
-#else
-using AttributePathExpandIterator = ::chip::app::AttributePathExpandIteratorEmber;
-#endif // CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-#endif // CHIP_CONFIG_USE_EMBER_DATA_MODEL && CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
+/**
+ * AttributePathExpandIterator is used to iterate over a linked list of AttributePathParams-s.
+ * The AttributePathExpandIterator is copiable, however, the given cluster info must be valid when calling Next().
+ *
+ * AttributePathExpandIterator will expand attribute paths with wildcards, and only emit existing paths for
+ * AttributePathParams with wildcards. For AttributePathParams with a concrete path (i.e. does not contain wildcards),
+ * AttributePathExpandIterator will emit them as-is.
+ *
+ * The typical use of AttributePathExpandIterator may look like:
+ * ConcreteAttributePath path;
+ * for (AttributePathExpandIterator iterator(AttributePathParams); iterator.Get(path); iterator.Next()) {...}
+ *
+ * The iterator does not copy the given AttributePathParams. The given AttributePathParams must remain valid when using the
+ * iterator. If the set of endpoints, clusters, or attributes that are supported changes, AttributePathExpandIterator must be
+ * reinitialized.
+ *
+ * A initialized iterator will return the first valid path, no need to call Next() before calling Get() for the first time.
+ *
+ * Note: Next() and Get() are two separate operations by design since a possible call of this iterator might be:
+ * - Get()
+ * - Chunk full, return
+ * - In a new chunk, Get()
+ *
+ * TODO: The AttributePathParams may support a group id, the iterator should be able to call group data provider to expand the group
+ * id.
+ */
+class AttributePathExpandIterator
+{
+public:
+    AttributePathExpandIterator(DataModel::Provider * provider, SingleLinkedListNode<AttributePathParams> * attributePath);
+
+    /**
+     * Proceed the iterator to the next attribute path in the given cluster info.
+     *
+     * Returns false if AttributePathExpandIteratorDataModeDataModel has exhausted all paths in the given AttributePathParams list.
+     */
+    bool Next();
+
+    /**
+     * Fills the aPath with the path the iterator currently points to.
+     * Returns false if the iterator is not pointing to a valid path (i.e. it has exhausted the cluster info).
+     */
+    bool Get(ConcreteAttributePath & aPath)
+    {
+        aPath = mOutputPath;
+        return (mpAttributePath != nullptr);
+    }
+
+    /**
+     * Reset the iterator to the beginning of current cluster if we are in the middle of expanding a wildcard attribute id for some
+     * cluster.
+     *
+     * When attributes are changed in the middle of expanding a wildcard attribute, we need to reset the iterator, to provide the
+     * client with a consistent state of the cluster.
+     */
+    void ResetCurrentCluster();
+
+    /** Start iterating over the given `paths` */
+    inline void ResetTo(SingleLinkedListNode<AttributePathParams> * paths)
+    {
+        *this = AttributePathExpandIterator(mDataModelProvider, paths);
+    }
+
+private:
+    DataModel::Provider * mDataModelProvider;
+    SingleLinkedListNode<AttributePathParams> * mpAttributePath;
+    ConcreteAttributePath mOutputPath;
+
+    /// Move to the next endpoint/cluster/attribute triplet that is valid given
+    /// the current mOutputPath and mpAttributePath
+    ///
+    /// returns true if such a next value was found.
+    bool AdvanceOutputPath();
+
+    /// Get the next attribute ID in mOutputPath(endpoint/cluster) if one is available.
+    /// Will start from the beginning if current mOutputPath.mAttributeId is kInvalidAttributeId
+    ///
+    /// Respects path expansion/values in mpAttributePath
+    ///
+    /// Handles Global attributes (which are returned at the end)
+    std::optional<AttributeId> NextAttributeId();
+
+    /// Get the next cluster ID in mOutputPath(endpoint) if one is available.
+    /// Will start from the beginning if current mOutputPath.mClusterId is kInvalidClusterId
+    ///
+    /// Respects path expansion/values in mpAttributePath
+    std::optional<ClusterId> NextClusterId();
+
+    /// Get the next endpoint ID in mOutputPath if one is available.
+    /// Will start from the beginning if current mOutputPath.mEndpointId is kInvalidEndpointId
+    ///
+    /// Respects path expansion/values in mpAttributePath
+    std::optional<ClusterId> NextEndpointId();
+
+    /// Checks if the given attributeId is valid for the current mOutputPath(endpoint/cluster)
+    ///
+    /// Meaning that it is known to the data model OR it is a always-there global attribute.
+    bool IsValidAttributeId(AttributeId attributeId);
+};
 
 } // namespace app
 } // namespace chip
diff --git a/src/app/AttributeValueEncoder.h b/src/app/AttributeValueEncoder.h
index 8943678..a0f8fbb 100644
--- a/src/app/AttributeValueEncoder.h
+++ b/src/app/AttributeValueEncoder.h
@@ -115,8 +115,7 @@
      *
      * When EncodeList returns an error, the consumers must abort the encoding, and return the exact error to the caller.
      *
-     * TODO: Can we hold a error state in the AttributeValueEncoder itself so functions in ember-compatibility-functions don't have
-     * to rely on the above assumption?
+     * TODO: Can we hold a error state in the AttributeValueEncoder itself?
      *
      * Consumers are allowed to make either one call to EncodeList or one call to Encode to handle a read.
      *
diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn
index 8849d39..5fc0d0c 100644
--- a/src/app/BUILD.gn
+++ b/src/app/BUILD.gn
@@ -75,31 +75,9 @@
     "NON_SPEC_COMPLIANT_OTA_ACTION_DELAY_FLOOR=${non_spec_compliant_ota_action_delay_floor}",
     "CHIP_DEVICE_CONFIG_DYNAMIC_SERVER=${chip_build_controller_dynamic_server}",
     "CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP=${chip_enable_busy_handling_for_operational_session_setup}",
-    "CHIP_CONFIG_DATA_MODEL_CHECK_DIE_ON_FAILURE=${chip_data_model_check_die_on_failure}",
     "CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING=${chip_data_model_extra_logging}",
   ]
 
-  if (chip_use_data_model_interface == "disabled") {
-    defines += [
-      "CHIP_CONFIG_USE_DATA_MODEL_INTERFACE=0",
-      "CHIP_CONFIG_USE_EMBER_DATA_MODEL=1",
-    ]
-  } else if (chip_use_data_model_interface == "check") {
-    defines += [
-      "CHIP_CONFIG_USE_DATA_MODEL_INTERFACE=1",
-      "CHIP_CONFIG_USE_EMBER_DATA_MODEL=1",
-    ]
-  } else {
-    # only one of disabled/check/enabled must be used
-    assert(chip_use_data_model_interface == "enabled",
-           "chip_use_data_model_interface must use a supported value")
-
-    defines += [
-      "CHIP_CONFIG_USE_DATA_MODEL_INTERFACE=1",
-      "CHIP_CONFIG_USE_EMBER_DATA_MODEL=0",
-    ]
-  }
-
   visibility = [ ":app_config" ]
 }
 
@@ -221,6 +199,8 @@
     #
     #       This breaks having `.h` and `.cpp` based off the same compilation unit and
     #       should ideally be cleaned up.
+    "reporting/Read.cpp",
+    "reporting/Read.h",
     "reporting/reporting.h",
   ]
 
@@ -253,29 +233,6 @@
 
   public_configs = [ "${chip_root}/src:includes" ]
 
-  if (chip_use_data_model_interface == "disabled") {
-    sources += [
-      "reporting/Read-Ember.cpp",
-      "reporting/Read-Ember.h",
-    ]
-  } else if (chip_use_data_model_interface == "check") {
-    sources += [
-      "reporting/Read-Checked.cpp",
-      "reporting/Read-Checked.h",
-      "reporting/Read-DataModel.cpp",
-      "reporting/Read-DataModel.h",
-      "reporting/Read-Ember.cpp",
-      "reporting/Read-Ember.h",
-    ]
-    public_deps += [ "${chip_root}/src/app/data-model-provider" ]
-  } else {  # enabled
-    sources += [
-      "reporting/Read-DataModel.cpp",
-      "reporting/Read-DataModel.h",
-    ]
-    public_deps += [ "${chip_root}/src/app/data-model-provider" ]
-  }
-
   if (chip_enable_read_client) {
     sources += [ "ReadClient.cpp" ]
   }
@@ -440,6 +397,8 @@
   output_name = "libCHIPDataModel"
 
   sources = [
+    "AttributePathExpandIterator.cpp",
+    "AttributePathExpandIterator.h",
     "AttributePathExpandIterator.h",
     "AttributePersistenceProvider.h",
     "ChunkedWriteCallback.cpp",
@@ -479,6 +438,7 @@
     ":global-attributes",
     ":interaction-model",
     "${chip_root}/src/app/data-model",
+    "${chip_root}/src/app/data-model-provider",
     "${chip_root}/src/app/icd/server:icd-server-config",
     "${chip_root}/src/app/util:callbacks",
     "${chip_root}/src/lib/address_resolve",
@@ -488,32 +448,6 @@
     "${chip_root}/src/system",
   ]
 
-  if (chip_use_data_model_interface == "disabled") {
-    sources += [
-      "AttributePathExpandIterator-Ember.cpp",
-      "AttributePathExpandIterator-Ember.h",
-      "AttributePathExpandIterator.h",
-    ]
-  } else if (chip_use_data_model_interface == "check") {
-    sources += [
-      "AttributePathExpandIterator-Checked.cpp",
-      "AttributePathExpandIterator-Checked.h",
-      "AttributePathExpandIterator-DataModel.cpp",
-      "AttributePathExpandIterator-DataModel.h",
-      "AttributePathExpandIterator-Ember.cpp",
-      "AttributePathExpandIterator-Ember.h",
-      "AttributePathExpandIterator.h",
-    ]
-    public_deps += [ "${chip_root}/src/app/data-model-provider" ]
-  } else {  # enabled
-    sources += [
-      "AttributePathExpandIterator-DataModel.cpp",
-      "AttributePathExpandIterator-DataModel.h",
-      "AttributePathExpandIterator.h",
-    ]
-    public_deps += [ "${chip_root}/src/app/data-model-provider" ]
-  }
-
   if (chip_enable_read_client) {
     sources += [
       "BufferedReadCallback.cpp",
diff --git a/src/app/CommandHandlerImpl.cpp b/src/app/CommandHandlerImpl.cpp
index 80373dc..b01343b 100644
--- a/src/app/CommandHandlerImpl.cpp
+++ b/src/app/CommandHandlerImpl.cpp
@@ -475,25 +475,6 @@
     }
     VerifyOrReturnError(err == CHIP_NO_ERROR, Status::Failure);
 
-    // Per spec, we do the "is this a timed command?" check for every path, but
-    // since all paths that fail it just get silently discarded we can do it
-    // once up front and discard all the paths at once.  Ordering with respect
-    // to ACL and command presence checks does not matter, because the behavior
-    // is the same for all of them: ignore the path.
-#if !CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-
-    // Without data model interface, we can query individual commands.
-    // Data model interface queries commands by a full path so we need endpointID as well.
-    //
-    // Since this is a performance update and group commands are never timed,
-    // missing this should not be that noticeable.
-    if (CommandNeedsTimedInvoke(clusterId, commandId))
-    {
-        // Group commands are never timed.
-        return Status::Success;
-    }
-#endif
-
     // No check for `CommandIsFabricScoped` unlike in `ProcessCommandDataIB()` since group commands
     // always have an accessing fabric, by definition.
 
diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp
index 49baa70..0dd4df6 100644
--- a/src/app/InteractionModelEngine.cpp
+++ b/src/app/InteractionModelEngine.cpp
@@ -40,7 +40,6 @@
 #include <app/data-model-provider/OperationTypes.h>
 #include <app/util/IMClusterCommandHandler.h>
 #include <app/util/af-types.h>
-#include <app/util/ember-compatibility-functions.h>
 #include <app/util/endpoint-config-api.h>
 #include <lib/core/CHIPError.h>
 #include <lib/core/DataModelTypes.h>
@@ -51,11 +50,9 @@
 #include <lib/support/FibonacciUtils.h>
 #include <protocols/interaction_model/StatusCode.h>
 
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
 // TODO: defaulting to codegen should eventually be an application choice and not
 //       hard-coded in the interaction model
 #include <app/codegen-data-model-provider/Instance.h>
-#endif
 
 namespace chip {
 namespace app {
@@ -87,8 +84,6 @@
     return (Access::GetAccessControl().Check(aSubjectDescriptor, requestPath, requiredPrivilege) == CHIP_NO_ERROR);
 }
 
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-
 bool MayHaveAccessibleEventPathForEndpoint(DataModel::Provider * aProvider, EndpointId aEndpoint,
                                            const EventPathParams & aEventPath, const Access::SubjectDescriptor & aSubjectDescriptor)
 {
@@ -132,72 +127,6 @@
     return false;
 }
 
-#else
-
-/**
- * Helper to handle wildcard clusters in the event path.
- */
-bool MayHaveAccessibleEventPathForEndpoint(EndpointId aEndpoint, const EventPathParams & aEventPath,
-                                           const Access::SubjectDescriptor & aSubjectDescriptor)
-{
-    if (aEventPath.HasWildcardClusterId())
-    {
-        auto * endpointType = emberAfFindEndpointType(aEndpoint);
-        if (endpointType == nullptr)
-        {
-            // Not going to have any valid paths in here.
-            return false;
-        }
-
-        for (decltype(endpointType->clusterCount) idx = 0; idx < endpointType->clusterCount; ++idx)
-        {
-            bool mayHaveAccessiblePath = MayHaveAccessibleEventPathForEndpointAndCluster(
-                ConcreteClusterPath(aEndpoint, endpointType->cluster[idx].clusterId), aEventPath, aSubjectDescriptor);
-            if (mayHaveAccessiblePath)
-            {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    auto * cluster = emberAfFindServerCluster(aEndpoint, aEventPath.mClusterId);
-    if (cluster == nullptr)
-    {
-        // Nothing valid here.
-        return false;
-    }
-    return MayHaveAccessibleEventPathForEndpointAndCluster(ConcreteClusterPath(aEndpoint, cluster->clusterId), aEventPath,
-                                                           aSubjectDescriptor);
-}
-
-bool MayHaveAccessibleEventPath(const EventPathParams & aEventPath, const Access::SubjectDescriptor & aSubjectDescriptor)
-{
-    if (!aEventPath.HasWildcardEndpointId())
-    {
-        // No need to check whether the endpoint is enabled, because
-        // emberAfFindEndpointType returns null for disabled endpoints.
-        return MayHaveAccessibleEventPathForEndpoint(aEventPath.mEndpointId, aEventPath, aSubjectDescriptor);
-    }
-
-    for (uint16_t endpointIndex = 0; endpointIndex < emberAfEndpointCount(); ++endpointIndex)
-    {
-        if (!emberAfEndpointIndexIsEnabled(endpointIndex))
-        {
-            continue;
-        }
-        if (MayHaveAccessibleEventPathForEndpoint(emberAfEndpointFromIndex(endpointIndex), aEventPath, aSubjectDescriptor))
-        {
-            return true;
-        }
-    }
-
-    // none of the paths matched
-    return false;
-}
-#endif
-
 } // namespace
 
 class AutoReleaseSubscriptionInfoIterator
@@ -245,15 +174,6 @@
 
     StatusIB::RegisterErrorFormatter();
 
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL && CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-    ChipLogError(InteractionModel, "WARNING ┌────────────────────────────────────────────────────");
-    ChipLogError(InteractionModel, "WARNING │ Interaction Model Engine running in 'Checked' mode.");
-    ChipLogError(InteractionModel, "WARNING │ This executes BOTH ember and data-model code paths.");
-    ChipLogError(InteractionModel, "WARNING │ which is inefficient and consumes more flash space.");
-    ChipLogError(InteractionModel, "WARNING │ This should be done for testing only.");
-    ChipLogError(InteractionModel, "WARNING └────────────────────────────────────────────────────");
-#endif
-
     mState = State::kInitialized;
     return CHIP_NO_ERROR;
 }
@@ -725,11 +645,7 @@
 
         // The definition of "valid path" is "path exists and ACL allows
         // access".  We need to do some expansion of wildcards to handle that.
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
         aHasValidEventPath = MayHaveAccessibleEventPath(mDataModelProvider, eventPath, aSubjectDescriptor);
-#else
-        aHasValidEventPath = MayHaveAccessibleEventPath(eventPath, aSubjectDescriptor);
-#endif
     }
 
     if (err == CHIP_ERROR_END_OF_TLV)
@@ -1628,19 +1544,7 @@
 
 bool InteractionModelEngine::IsExistentAttributePath(const ConcreteAttributePath & path)
 {
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
-    bool providerResult = GetDataModelProvider()->GetAttributeInfo(path).has_value();
-
-    bool emberResult = emberAfContainsAttribute(path.mEndpointId, path.mClusterId, path.mAttributeId);
-
-    // Ensure that Provider interface and ember are IDENTICAL in attribute location (i.e. "check" mode)
-    VerifyOrDie(providerResult == emberResult);
-#endif
     return GetDataModelProvider()->GetAttributeInfo(path).has_value();
-#else
-    return emberAfContainsAttribute(path.mEndpointId, path.mClusterId, path.mAttributeId);
-#endif
 }
 
 void InteractionModelEngine::RemoveDuplicateConcreteAttributePath(SingleLinkedListNode<AttributePathParams> *& aAttributePaths)
@@ -1767,8 +1671,6 @@
 void InteractionModelEngine::DispatchCommand(CommandHandlerImpl & apCommandObj, const ConcreteCommandPath & aCommandPath,
                                              TLV::TLVReader & apPayload)
 {
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-
     Access::SubjectDescriptor subjectDescriptor = apCommandObj.GetSubjectDescriptor();
 
     DataModel::InvokeRequest request;
@@ -1785,26 +1687,6 @@
     {
         apCommandObj.AddStatus(aCommandPath, status->GetStatusCode());
     }
-#else
-    CommandHandlerInterface * handler =
-        CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(aCommandPath.mEndpointId, aCommandPath.mClusterId);
-
-    if (handler)
-    {
-        CommandHandlerInterface::HandlerContext context(apCommandObj, aCommandPath, apPayload);
-        handler->InvokeCommand(context);
-
-        //
-        // If the command was handled, don't proceed any further and return successfully.
-        //
-        if (context.mCommandHandled)
-        {
-            return;
-        }
-    }
-
-    DispatchSingleClusterCommand(aCommandPath, apPayload, &apCommandObj);
-#endif // CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
 }
 
 Protocols::InteractionModel::Status InteractionModelEngine::ValidateCommandCanBeDispatched(const DataModel::InvokeRequest & request)
@@ -1836,13 +1718,10 @@
                                      .endpoint    = aRequest.path.mEndpointId,
                                      .requestType = Access::RequestType::kCommandInvokeRequest,
                                      .entityId    = aRequest.path.mCommandId };
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
     std::optional<DataModel::CommandInfo> commandInfo = mDataModelProvider->GetAcceptedCommandInfo(aRequest.path);
     Access::Privilege minimumRequiredPrivilege =
         commandInfo.has_value() ? commandInfo->invokePrivilege : Access::Privilege::kOperate;
-#else
-    Access::Privilege minimumRequiredPrivilege = RequiredPrivilege::ForInvokeCommand(aRequest.path);
-#endif
+
     CHIP_ERROR err = Access::GetAccessControl().Check(*aRequest.subjectDescriptor, requestPath, minimumRequiredPrivilege);
     if (err != CHIP_NO_ERROR)
     {
@@ -1858,17 +1737,12 @@
 
 Protocols::InteractionModel::Status InteractionModelEngine::CheckCommandFlags(const DataModel::InvokeRequest & aRequest)
 {
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
     std::optional<DataModel::CommandInfo> commandInfo = mDataModelProvider->GetAcceptedCommandInfo(aRequest.path);
     // This is checked by previous validations, so it should not happen
     VerifyOrDie(commandInfo.has_value());
 
     const bool commandNeedsTimedInvoke = commandInfo->flags.Has(DataModel::CommandQualityFlags::kTimed);
     const bool commandIsFabricScoped   = commandInfo->flags.Has(DataModel::CommandQualityFlags::kFabricScoped);
-#else
-    const bool commandNeedsTimedInvoke         = CommandNeedsTimedInvoke(aRequest.path.mClusterId, aRequest.path.mCommandId);
-    const bool commandIsFabricScoped           = CommandIsFabricScoped(aRequest.path.mClusterId, aRequest.path.mCommandId);
-#endif
 
     if (commandNeedsTimedInvoke && !aRequest.invokeFlags.Has(DataModel::InvokeFlags::kTimed))
     {
@@ -1893,13 +1767,9 @@
 
 Protocols::InteractionModel::Status InteractionModelEngine::CheckCommandExistence(const ConcreteCommandPath & aCommandPath)
 {
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
     auto provider = GetDataModelProvider();
     if (provider->GetAcceptedCommandInfo(aCommandPath).has_value())
     {
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
-        VerifyOrDie(ServerClusterCommandExists(aCommandPath) == Protocols::InteractionModel::Status::Success);
-#endif
         return Protocols::InteractionModel::Status::Success;
     }
 
@@ -1907,9 +1777,6 @@
     //
     if (provider->GetClusterInfo(aCommandPath).has_value())
     {
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
-        VerifyOrDie(ServerClusterCommandExists(aCommandPath) == Protocols::InteractionModel::Status::UnsupportedCommand);
-#endif
         return Protocols::InteractionModel::Status::UnsupportedCommand; // cluster exists, so command is invalid
     }
 
@@ -1920,22 +1787,13 @@
     {
         if (endpoint == aCommandPath.mEndpointId)
         {
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
-            VerifyOrDie(ServerClusterCommandExists(aCommandPath) == Protocols::InteractionModel::Status::UnsupportedCluster);
-#endif
             // endpoint exists, so cluster is invalid
             return Protocols::InteractionModel::Status::UnsupportedCluster;
         }
     }
 
     // endpoint not found
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
-    VerifyOrDie(ServerClusterCommandExists(aCommandPath) == Protocols::InteractionModel::Status::UnsupportedEndpoint);
-#endif
     return Protocols::InteractionModel::Status::UnsupportedEndpoint;
-#else
-    return ServerClusterCommandExists(aCommandPath);
-#endif
 }
 
 DataModel::Provider * InteractionModelEngine::SetDataModelProvider(DataModel::Provider * model)
@@ -1974,14 +1832,12 @@
 
 DataModel::Provider * InteractionModelEngine::GetDataModelProvider()
 {
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
     if (mDataModelProvider == nullptr)
     {
         // These should be called within the CHIP processing loop.
         assertChipStackLockedByCurrentThread();
         SetDataModelProvider(CodegenDataModelProviderInstance());
     }
-#endif
     return mDataModelProvider;
 }
 
diff --git a/src/app/WriteHandler.cpp b/src/app/WriteHandler.cpp
index 7a1bbc5..1e129ad 100644
--- a/src/app/WriteHandler.cpp
+++ b/src/app/WriteHandler.cpp
@@ -28,7 +28,6 @@
 #include <app/data-model-provider/OperationTypes.h>
 #include <app/reporting/Engine.h>
 #include <app/util/MatterCallbacks.h>
-#include <app/util/ember-compatibility-functions.h>
 #include <credentials/GroupDataProvider.h>
 #include <lib/core/CHIPError.h>
 #include <lib/support/CodeUtils.h>
@@ -74,10 +73,8 @@
 {
     VerifyOrReturnError(!mExchangeCtx, CHIP_ERROR_INCORRECT_STATE);
     VerifyOrReturnError(apWriteHandlerDelegate, CHIP_ERROR_INVALID_ARGUMENT);
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
     VerifyOrReturnError(apProvider, CHIP_ERROR_INVALID_ARGUMENT);
     mDataModelProvider = apProvider;
-#endif // CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
 
     mDelegate = apWriteHandlerDelegate;
     MoveToState(State::Initialized);
@@ -99,15 +96,12 @@
     DeliverFinalListWriteEnd(false /* wasSuccessful */);
     mExchangeCtx.Release();
     mStateFlags.Clear(StateBits::kSuppressResponse);
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
     mDataModelProvider = nullptr;
-#endif // CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
     MoveToState(State::Uninitialized);
 }
 
 std::optional<bool> WriteHandler::IsListAttributePath(const ConcreteAttributePath & path)
 {
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
     if (mDataModelProvider == nullptr)
     {
 #if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING
@@ -123,15 +117,6 @@
     }
 
     return info->flags.Has(DataModel::AttributeQualityFlags::kListAttribute);
-#else
-    constexpr uint8_t kListAttributeType = 0x48;
-    const auto attributeMetadata         = GetAttributeMetadata(path);
-    if (attributeMetadata == nullptr)
-    {
-        return std::nullopt;
-    }
-    return (attributeMetadata->attributeType == kListAttributeType);
-#endif
 }
 
 Status WriteHandler::HandleWriteRequestMessage(Messaging::ExchangeContext * apExchangeContext,
@@ -613,9 +598,7 @@
     // our callees hand out Status as well.
     Status status = Status::InvalidAction;
 
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
     mLastSuccessfullyWrittenPath = std::nullopt;
-#endif // CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
 
     reader.Init(std::move(aPayload));
 
@@ -773,7 +756,6 @@
 {
     // Writes do not have a checked-path. If data model interface is enabled (both checked and only version)
     // the write is done via the DataModel interface
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
     VerifyOrReturnError(mDataModelProvider != nullptr, CHIP_ERROR_INCORRECT_STATE);
 
     DataModel::WriteAttributeRequest request;
@@ -790,9 +772,6 @@
     mLastSuccessfullyWrittenPath = status.IsSuccess() ? std::make_optional(aPath) : std::nullopt;
 
     return AddStatusInternal(aPath, StatusIB(status.GetStatusCode()));
-#else
-    return WriteSingleClusterData(aSubject, aPath, aData, this);
-#endif // CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
 }
 
 } // namespace app
diff --git a/src/app/WriteHandler.h b/src/app/WriteHandler.h
index 33c068b..fa1d324 100644
--- a/src/app/WriteHandler.h
+++ b/src/app/WriteHandler.h
@@ -200,10 +200,8 @@
     Optional<ConcreteAttributePath> mProcessingAttributePath;
     Optional<AttributeAccessToken> mACLCheckCache = NullOptional;
 
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
     DataModel::Provider * mDataModelProvider = nullptr;
     std::optional<ConcreteAttributePath> mLastSuccessfullyWrittenPath;
-#endif
 
     // This may be a "fake" pointer or a real delegate pointer, depending
     // on CHIP_CONFIG_STATIC_GLOBAL_INTERACTION_MODEL_ENGINE setting.
diff --git a/src/app/chip_data_model.cmake b/src/app/chip_data_model.cmake
index 11db6d4..75e2d8a 100644
--- a/src/app/chip_data_model.cmake
+++ b/src/app/chip_data_model.cmake
@@ -70,17 +70,12 @@
 #
 function(chip_configure_data_model APP_TARGET)
     set(SCOPE PRIVATE)
-    set(ADD_EMBER_INTERFACE_FILES TRUE)
-    cmake_parse_arguments(ARG "SKIP_EMBER_INTERFACE" "SCOPE;ZAP_FILE;IDL" "EXTERNAL_CLUSTERS" ${ARGN})
+    cmake_parse_arguments(ARG "" "SCOPE;ZAP_FILE;IDL" "EXTERNAL_CLUSTERS" ${ARGN})
 
     if(ARG_SCOPE)
         set(SCOPE ${ARG_SCOPE})
     endif()
 
-    if(ARG_SKIP_EMBER_INTERFACE)
-        set(ADD_EMBER_INTERFACE_FILES FALSE)
-    endif()
-
     # CMAKE data model auto-includes the server side implementation
     target_sources(${APP_TARGET} ${SCOPE}
         ${CHIP_APP_BASE_DIR}/server/AclStorage.cpp
@@ -173,10 +168,4 @@
         ${APP_GEN_FILES}
         ${APP_TEMPLATES_GEN_FILES}
     )
-
-    if(ADD_EMBER_INTERFACE_FILES)
-        target_sources(${APP_TARGET} ${SCOPE}
-           ${CHIP_APP_BASE_DIR}/util/ember-compatibility-functions.cpp
-        )
-    endif()
 endfunction()
diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni
index cc99894..9f4ed59 100644
--- a/src/app/chip_data_model.gni
+++ b/src/app/chip_data_model.gni
@@ -213,11 +213,6 @@
         "${_app_root}/util/ember-io-storage.cpp",
         "${_app_root}/util/util.cpp",
       ]
-
-      if (chip_use_data_model_interface != "enabled") {
-        # This applies to "check" or "disabled" (i.e. use ember-only or use ember for double-checking)
-        sources += [ "${_app_root}/util/ember-compatibility-functions.cpp" ]
-      }
     }
 
     if (defined(invoker.zap_file)) {
diff --git a/src/app/clusters/microwave-oven-control-server/microwave-oven-control-server.cpp b/src/app/clusters/microwave-oven-control-server/microwave-oven-control-server.cpp
index c012ddb..75b7e7d 100644
--- a/src/app/clusters/microwave-oven-control-server/microwave-oven-control-server.cpp
+++ b/src/app/clusters/microwave-oven-control-server/microwave-oven-control-server.cpp
@@ -24,7 +24,6 @@
 #include <app/clusters/mode-base-server/mode-base-server.h>
 #include <app/reporting/reporting.h>
 #include <app/util/attribute-storage.h>
-#include <app/util/ember-compatibility-functions.h>
 
 using namespace chip;
 using namespace chip::app;
@@ -250,12 +249,8 @@
     {
         ConcreteCommandPath commandPath(mEndpointId, OperationalState::Id, OperationalState::Commands::Start::Id);
 
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
-        bool commandExists = ServerClusterCommandExists(commandPath) == Status::Success;
-#else
         bool commandExists =
             InteractionModelEngine::GetInstance()->GetDataModelProvider()->GetAcceptedCommandInfo(commandPath).has_value();
-#endif
         VerifyOrExit(
             commandExists, status = Status::InvalidCommand; ChipLogError(
                 Zcl,
diff --git a/src/app/clusters/pump-configuration-and-control-server/pump-configuration-and-control-server.cpp b/src/app/clusters/pump-configuration-and-control-server/pump-configuration-and-control-server.cpp
index 63bd6a2..749c80d 100644
--- a/src/app/clusters/pump-configuration-and-control-server/pump-configuration-and-control-server.cpp
+++ b/src/app/clusters/pump-configuration-and-control-server/pump-configuration-and-control-server.cpp
@@ -25,7 +25,6 @@
 #include <app/InteractionModelEngine.h>
 #include <app/util/attribute-storage.h>
 #include <app/util/config.h>
-#include <app/util/ember-compatibility-functions.h>
 
 using namespace chip;
 using namespace chip::app;
diff --git a/src/app/codegen-data-model-provider/tests/InteractionModelTemporaryOverrides.cpp b/src/app/codegen-data-model-provider/tests/InteractionModelTemporaryOverrides.cpp
index e771827..fd37e05 100644
--- a/src/app/codegen-data-model-provider/tests/InteractionModelTemporaryOverrides.cpp
+++ b/src/app/codegen-data-model-provider/tests/InteractionModelTemporaryOverrides.cpp
@@ -14,68 +14,7 @@
  *    See the License for the specific language governing permissions and
  *    limitations under the License.
  */
-#include <app/AttributeEncodeState.h>
-#include <app/AttributeReportBuilder.h>
-#include <app/CommandHandler.h>
 #include <app/ConcreteAttributePath.h>
-#include <app/ConcreteCommandPath.h>
-#include <app/WriteHandler.h>
-#include <app/util/attribute-storage.h>
-
-using chip::Protocols::InteractionModel::Status;
-
-// TODO: most of the functions here are part of EmberCompatibilityFunctions and is NOT decoupled
-//       from IM current, but it SHOULD be
-//       Open issue https://github.com/project-chip/connectedhomeip/issues/34137 for this work.
-namespace chip {
-namespace app {
-
-bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath)
-{
-    // TODO: this is just a noop which may be potentially invalid
-    return true;
-}
-
-bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion)
-{
-    // TODO: this is just a noop which may be potentially invalid
-    return true;
-}
-
-const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aPath)
-{
-    return emberAfLocateAttributeMetadata(aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId);
-}
-
-Status ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath)
-{
-    // TODO: this is just a noop which may be potentially invalid
-    return Status::Success;
-}
-
-Status CheckEventSupportStatus(const ConcreteEventPath & aPath)
-{
-    // TODO: this is just a noop which may be potentially invalid
-    return Status::Success;
-}
-
-CHIP_ERROR WriteSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath,
-                                  TLV::TLVReader & aReader, WriteHandler * apWriteHandler)
-{
-    // this is just to get things to compile. eventually this method should NOT be used
-    return CHIP_ERROR_NOT_IMPLEMENTED;
-}
-
-CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
-                                 const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
-                                 AttributeEncodeState * apEncoderState)
-{
-    // this is just to get things to compile. eventually this method should NOT be used
-    return CHIP_ERROR_NOT_IMPLEMENTED;
-}
-
-} // namespace app
-} // namespace chip
 
 void MatterReportingAttributeChangeCallback(const chip::app::ConcreteAttributePath & aPath)
 {
diff --git a/src/app/common_flags.gni b/src/app/common_flags.gni
index 4dbbcb4..30678df 100644
--- a/src/app/common_flags.gni
+++ b/src/app/common_flags.gni
@@ -25,22 +25,6 @@
   # communicated to OperationalSessionSetup API consumers.
   chip_enable_busy_handling_for_operational_session_setup = true
 
-  # Data model interface usage:
-  #   - disabled: does not use data model interface at all
-  #   - check:    runs BOTH datamodel and non-data-model (if possible) functionality and compares results
-  #   - enabled:  runs only the data model interface (does not use the legacy code)
-  if (matter_enable_recommended && current_os == "linux") {
-    chip_use_data_model_interface = "check"
-  } else {
-    chip_use_data_model_interface = "enabled"
-  }
-
-  # Whether we call `chipDie` on DM `check` errors
-  #
-  # If/once the chip_use_data_model_interface flag is removed or does not support
-  # a `check` option, this should alwo be removed
-  chip_data_model_check_die_on_failure = false
-
   # This controls if more logging is supposed to be enabled into the data models.
   # This is an optimization for small-flash size devices as extra logging requires
   # additional flash for messages & code for formatting.
diff --git a/src/app/dynamic_server/AccessControl.cpp b/src/app/dynamic_server/AccessControl.cpp
index d091b9a..9f39040 100644
--- a/src/app/dynamic_server/AccessControl.cpp
+++ b/src/app/dynamic_server/AccessControl.cpp
@@ -25,11 +25,6 @@
 #include <lib/core/CHIPError.h>
 #include <lib/core/Global.h>
 
-// TODO: this include is unclear as dynamic server should NOT link those.
-//       we should probably have some separate includes here for dynamic
-//       server
-#include <app/util/ember-compatibility-functions.h>
-
 using namespace chip;
 using namespace chip::Access;
 using namespace chip::app::Clusters;
@@ -44,7 +39,16 @@
 public:
     bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint) override
     {
-        return app::IsDeviceTypeOnEndpoint(deviceType, endpoint);
+        chip::app::DataModel::Provider * model = chip::app::InteractionModelEngine::GetInstance()->GetDataModelProvider();
+
+        for (auto type = model->FirstDeviceType(endpoint); type.has_value(); type = model->NextDeviceType(endpoint, *type))
+        {
+            if (type->deviceTypeId == deviceType)
+            {
+                return true;
+            }
+        }
+        return false;
     }
 };
 
diff --git a/src/app/dynamic_server/DynamicDispatcher.cpp b/src/app/dynamic_server/DynamicDispatcher.cpp
index 0c9825d..ba4525e 100644
--- a/src/app/dynamic_server/DynamicDispatcher.cpp
+++ b/src/app/dynamic_server/DynamicDispatcher.cpp
@@ -15,8 +15,6 @@
  *    See the License for the specific language governing permissions and
  *    limitations under the License.
  */
-#include <app/util/ember-compatibility-functions.h>
-
 #include <access/SubjectDescriptor.h>
 #include <app-common/zap-generated/callback.h>
 #include <app-common/zap-generated/cluster-objects.h>
@@ -43,9 +41,8 @@
 
 /**
  * This file defines the APIs needed to handle interaction model dispatch.
- * These are the APIs normally defined in
- * src/app/util/ember-compatibility-functions.cpp and the generated
- * IMClusterCommandHandler.cpp but we want a different implementation of these
+ * These are the APIs normally defined generated ember code,
+ * however we want a different implementation of these
  * to enable more dynamic behavior, since not all framework consumers will be
  * implementing the same server clusters.
  */
@@ -69,129 +66,6 @@
 using Access::SubjectDescriptor;
 using Protocols::InteractionModel::Status;
 
-namespace {
-
-bool IsSupportedGlobalAttribute(AttributeId aAttribute)
-{
-    // We don't have any non-global attributes.
-    using namespace Globals::Attributes;
-
-    for (auto & attr : GlobalAttributesNotInMetadata)
-    {
-        if (attr == aAttribute)
-        {
-            return true;
-        }
-    }
-
-    switch (aAttribute)
-    {
-    case FeatureMap::Id:
-        FALLTHROUGH;
-    case ClusterRevision::Id:
-        return true;
-    }
-
-    return false;
-}
-
-Status DetermineAttributeStatus(const ConcreteAttributePath & aPath, bool aIsWrite)
-{
-    // TODO: Consider making this configurable for applications that are not
-    // trying to be an OTA provider, though in practice it just affects which
-    // error is returned.
-    if (aPath.mEndpointId != kSupportedEndpoint)
-    {
-        return Status::UnsupportedEndpoint;
-    }
-
-    // TODO: Consider making this configurable for applications that are not
-    // trying to be an OTA provider, though in practice it just affects which
-    // error is returned.
-    if (aPath.mClusterId != OtaSoftwareUpdateProvider::Id)
-    {
-        return Status::UnsupportedCluster;
-    }
-
-    if (!IsSupportedGlobalAttribute(aPath.mAttributeId))
-    {
-        return Status::UnsupportedAttribute;
-    }
-
-    // No permissions for this for read, and none of these are writable for
-    // write.  The writable-or-not check happens before the ACL check.
-    return aIsWrite ? Status::UnsupportedWrite : Status::UnsupportedAccess;
-}
-
-} // anonymous namespace
-
-CHIP_ERROR ReadSingleClusterData(const SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
-                                 const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
-                                 AttributeEncodeState * aEncoderState)
-{
-    Status status = DetermineAttributeStatus(aPath, /* aIsWrite = */ false);
-    return aAttributeReports.EncodeAttributeStatus(aPath, StatusIB(status));
-}
-
-bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath)
-{
-    return DetermineAttributeStatus(aPath, /* aIsWrite = */ false) == Status::UnsupportedAccess;
-}
-
-Status ServerClusterCommandExists(const ConcreteCommandPath & aPath)
-{
-    // TODO: Consider making this configurable for applications that are not
-    // trying to be an OTA provider.
-    using namespace OtaSoftwareUpdateProvider::Commands;
-
-    if (aPath.mEndpointId != kSupportedEndpoint)
-    {
-        return Status::UnsupportedEndpoint;
-    }
-
-    if (aPath.mClusterId != OtaSoftwareUpdateProvider::Id)
-    {
-        return Status::UnsupportedCluster;
-    }
-
-    switch (aPath.mCommandId)
-    {
-    case QueryImage::Id:
-        FALLTHROUGH;
-    case ApplyUpdateRequest::Id:
-        FALLTHROUGH;
-    case NotifyUpdateApplied::Id:
-        return Status::Success;
-    }
-
-    return Status::UnsupportedCommand;
-}
-
-bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion)
-{
-    // Will never be called anyway; we have no attributes.
-    return false;
-}
-
-const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aConcreteClusterPath)
-{
-    // Note: This test does not make use of the real attribute metadata.
-    static EmberAfAttributeMetadata stub = { .defaultValue = EmberAfDefaultOrMinMaxAttributeValue(uint32_t(0)) };
-    return &stub;
-}
-
-bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint)
-{
-    return false;
-}
-
-CHIP_ERROR WriteSingleClusterData(const SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath,
-                                  TLV::TLVReader & aReader, WriteHandler * aWriteHandler)
-{
-    Status status = DetermineAttributeStatus(aPath, /* aIsWrite = */ true);
-    return aWriteHandler->AddStatus(aPath, status);
-}
-
 void DispatchSingleClusterCommand(const ConcreteCommandPath & aPath, TLV::TLVReader & aReader, CommandHandler * aCommandObj)
 {
     // This command passed ServerClusterCommandExists so we know it's one of our
@@ -240,11 +114,6 @@
     }
 }
 
-Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath)
-{
-    return Protocols::InteractionModel::Status::UnsupportedEvent;
-}
-
 } // namespace app
 } // namespace chip
 
diff --git a/src/app/reporting/Engine.cpp b/src/app/reporting/Engine.cpp
index 45ebdeb..284aa6f 100644
--- a/src/app/reporting/Engine.cpp
+++ b/src/app/reporting/Engine.cpp
@@ -24,11 +24,9 @@
 #include <app/data-model-provider/Provider.h>
 #include <app/icd/server/ICDServerConfig.h>
 #include <app/reporting/Engine.h>
-#include <app/reporting/Read-Checked.h>
 #include <app/reporting/Read.h>
 #include <app/reporting/reporting.h>
 #include <app/util/MatterCallbacks.h>
-#include <app/util/ember-compatibility-functions.h>
 #include <lib/core/DataModelTypes.h>
 #include <protocols/interaction_model/StatusCode.h>
 
@@ -47,17 +45,12 @@
 
 Status EventPathValid(DataModel::Provider * model, const ConcreteEventPath & eventPath)
 {
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-
     if (!model->GetClusterInfo(eventPath).has_value())
     {
         return model->EndpointExists(eventPath.mEndpointId) ? Status::UnsupportedCluster : Status::UnsupportedEndpoint;
     }
 
     return Status::Success;
-#else
-    return CheckEventSupportStatus(eventPath);
-#endif
 }
 
 } // namespace
@@ -1046,8 +1039,7 @@
 } // namespace app
 } // namespace chip
 
-// TODO: MatterReportingAttributeChangeCallback should just live in libCHIP,
-// instead of being in ember-compatibility-functions.  It does not depend on any
+// TODO: MatterReportingAttributeChangeCallback should just live in libCHIP, It does not depend on any
 // app-specific generated bits.
 void __attribute__((weak))
 MatterReportingAttributeChangeCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId)
diff --git a/src/app/reporting/Read-Checked.cpp b/src/app/reporting/Read-Checked.cpp
deleted file mode 100644
index 6e10fae..0000000
--- a/src/app/reporting/Read-Checked.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- *    Copyright (c) 2024 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-#include <app/reporting/Read-Checked.h>
-
-#include <app/data-model-provider/ActionReturnStatus.h>
-#include <app/reporting/Read-DataModel.h>
-#include <app/reporting/Read-Ember.h>
-#include <app/util/MatterCallbacks.h>
-#include <lib/support/CodeUtils.h>
-#include <lib/support/StringBuilder.h>
-
-namespace chip {
-namespace app {
-namespace reporting {
-namespace CheckedImpl {
-namespace {
-
-using DataModel::ActionReturnStatus;
-
-/// Checkpoints and saves the state (including error state) for a
-/// AttributeReportIBs::Builder
-class ScopedAttributeReportIBsBuilderState
-{
-public:
-    ScopedAttributeReportIBsBuilderState(AttributeReportIBs::Builder & builder) : mBuilder(builder), mError(mBuilder.GetError())
-    {
-        mBuilder.Checkpoint(mCheckpoint);
-    }
-
-    ~ScopedAttributeReportIBsBuilderState()
-    {
-        mBuilder.Rollback(mCheckpoint);
-        mBuilder.ResetError(mError);
-    }
-
-private:
-    AttributeReportIBs::Builder & mBuilder;
-    chip::TLV::TLVWriter mCheckpoint;
-    CHIP_ERROR mError;
-};
-
-} // namespace
-
-ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataModel, const Access::SubjectDescriptor & subjectDescriptor,
-                                       bool isFabricFiltered, AttributeReportIBs::Builder & reportBuilder,
-                                       const ConcreteReadAttributePath & path, AttributeEncodeState * encoderState)
-{
-    ChipLogDetail(DataManagement, "<RE:Run> Cluster %" PRIx32 ", Attribute %" PRIx32 " is dirty", path.mClusterId,
-                  path.mAttributeId);
-    DataModelCallbacks::GetInstance()->AttributeOperation(DataModelCallbacks::OperationType::Read,
-                                                          DataModelCallbacks::OperationOrder::Pre, path);
-
-    ActionReturnStatus statusEmber(CHIP_NO_ERROR);
-    uint32_t lengthWrittenEmber = 0;
-
-    // a copy for DM logic only. Ember changes state directly
-    // IMPORTANT: the copy MUST be taken BEFORE ember processes/changes encoderState inline.
-    AttributeEncodeState stateDm(encoderState);
-
-    {
-        ScopedAttributeReportIBsBuilderState builderState(reportBuilder); // temporary only
-        statusEmber =
-            EmberImpl::RetrieveClusterData(dataModel, subjectDescriptor, isFabricFiltered, reportBuilder, path, encoderState);
-        lengthWrittenEmber = reportBuilder.GetWriter()->GetLengthWritten();
-    }
-
-    ActionReturnStatus statusDm = DataModelImpl::RetrieveClusterData(dataModel, subjectDescriptor, isFabricFiltered, reportBuilder,
-                                                                     path, encoderState != nullptr ? &stateDm : nullptr);
-
-    if (statusEmber != statusDm)
-    {
-        ActionReturnStatus::StringStorage buffer;
-
-        // Note log + chipDie instead of VerifyOrDie so that breakpoints (and usage of rr)
-        // is easier to debug.
-        ChipLogError(Test, "Different return codes between ember and DM");
-        ChipLogError(Test, "  Ember status: %s", statusEmber.c_str(buffer));
-        ChipLogError(Test, "  DM status:    %s", statusDm.c_str(buffer));
-
-        // For time-dependent data, we may have size differences here: one data fitting in buffer
-        // while another not, resulting in different errors (success vs out of space).
-        //
-        // Make unit tests strict; otherwise allow it with potentially odd mismatch errors
-        // (in which case logs will be odd, however we also expect Checked versions to only
-        // run for a short period until we switch over to either ember or DM completely).
-#if CHIP_CONFIG_DATA_MODEL_CHECK_DIE_ON_FAILURE
-        chipDie();
-#endif
-    }
-
-    // data should be identical for most cases EXCEPT that for time-deltas (e.g. seconds since boot or similar)
-    // it may actually differ. As a result, the amount of data written in bytes MUST be the same, however if the rest of the
-    // data is not the same, we just print it out as a warning for manual inspection
-    //
-    // We have no direct access to TLV buffer data (especially given backing store splits)
-    // so for now we check that data length was identical.
-    //
-    // NOTE: RetrieveClusterData is responsible for encoding StatusIB errors in case of failures
-    //       so we validate length written requirements for BOTH success and failure.
-    //
-    // NOTE: data length is NOT reliable if the data content differs in encoding length. E.g. numbers changing
-    //       from 0xFF to 0x100 or similar will use up more space.
-    //       For unit tests we make the validation strict, however for runtime we just report an
-    //       error for different sizes.
-    if (lengthWrittenEmber != reportBuilder.GetWriter()->GetLengthWritten())
-    {
-        ChipLogError(Test, "Different written length: %" PRIu32 " (Ember) vs %" PRIu32 " (DataModel)", lengthWrittenEmber,
-                     reportBuilder.GetWriter()->GetLengthWritten());
-#if CHIP_CONFIG_DATA_MODEL_CHECK_DIE_ON_FAILURE
-        chipDie();
-#endif
-    }
-
-    // For chunked reads, the encoder state MUST be identical (since this is what controls
-    // where chunking resumes).
-    if (statusEmber.IsOutOfSpaceEncodingResponse())
-    {
-        // Encoder state MUST match on partial reads (used by chunking)
-        // specifically ReadViaAccessInterface in ember-compatibility-functions only
-        // sets the encoder state in case an error occurs.
-        if (encoderState != nullptr)
-        {
-            if (encoderState->AllowPartialData() != stateDm.AllowPartialData())
-            {
-                ChipLogError(Test, "Different partial data");
-                // NOTE: die on unit tests only, since partial data size may differ across
-                //       time-dependent data (very rarely because fast code, but still possible)
-#if CHIP_CONFIG_DATA_MODEL_CHECK_DIE_ON_FAILURE
-                chipDie();
-#endif
-            }
-            if (encoderState->CurrentEncodingListIndex() != stateDm.CurrentEncodingListIndex())
-            {
-                ChipLogError(Test, "Different partial data");
-                // NOTE: die on unit tests only, since partial data size may differ across
-                //       time-dependent data (very rarely because fast code, but still possible)
-#if CHIP_CONFIG_DATA_MODEL_CHECK_DIE_ON_FAILURE
-                chipDie();
-#endif
-            }
-        }
-    }
-
-    DataModelCallbacks::GetInstance()->AttributeOperation(DataModelCallbacks::OperationType::Read,
-                                                          DataModelCallbacks::OperationOrder::Post, path);
-
-    return statusDm;
-}
-
-bool IsClusterDataVersionEqualTo(DataModel::Provider * dataModel, const ConcreteClusterPath & path, DataVersion dataVersion)
-{
-    bool emberResult = EmberImpl::IsClusterDataVersionEqualTo(dataModel, path, dataVersion);
-    bool dmResult    = DataModelImpl::IsClusterDataVersionEqualTo(dataModel, path, dataVersion);
-
-    if (emberResult != dmResult)
-    {
-        ChipLogError(Test, "Different data model check result between ember (%s) and data model provider(%s)",
-                     emberResult ? "TRUE" : "FALSE", dmResult ? "TRUE" : "FALSE");
-#if CHIP_CONFIG_DATA_MODEL_CHECK_DIE_ON_FAILURE
-        chipDie();
-#endif
-    }
-
-    return dmResult;
-}
-
-} // namespace CheckedImpl
-} // namespace reporting
-} // namespace app
-} // namespace chip
diff --git a/src/app/reporting/Read-Checked.h b/src/app/reporting/Read-Checked.h
deleted file mode 100644
index 63ca9bf..0000000
--- a/src/app/reporting/Read-Checked.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *    Copyright (c) 2024 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-#pragma once
-
-#include "app/data-model-provider/ActionReturnStatus.h"
-#include <access/SubjectDescriptor.h>
-#include <app/AttributeEncodeState.h>
-#include <app/MessageDef/AttributeReportIBs.h>
-#include <app/data-model-provider/Provider.h>
-#include <lib/core/CHIPError.h>
-
-namespace chip {
-namespace app {
-namespace reporting {
-namespace CheckedImpl {
-
-DataModel::ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataModel,
-                                                  const Access::SubjectDescriptor & subjectDescriptor, bool isFabricFiltered,
-                                                  AttributeReportIBs::Builder & reportBuilder,
-                                                  const ConcreteReadAttributePath & path, AttributeEncodeState * encoderState);
-
-bool IsClusterDataVersionEqualTo(DataModel::Provider * dataModel, const ConcreteClusterPath & path, DataVersion dataVersion);
-
-} // namespace CheckedImpl
-} // namespace reporting
-} // namespace app
-} // namespace chip
diff --git a/src/app/reporting/Read-DataModel.h b/src/app/reporting/Read-DataModel.h
deleted file mode 100644
index ff4801b..0000000
--- a/src/app/reporting/Read-DataModel.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- *    Copyright (c) 2024 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-#pragma once
-
-#include "app/data-model-provider/ActionReturnStatus.h"
-#include <access/SubjectDescriptor.h>
-#include <app/AttributeEncodeState.h>
-#include <app/MessageDef/AttributeReportIBs.h>
-#include <app/data-model-provider/ActionReturnStatus.h>
-#include <app/data-model-provider/Provider.h>
-#include <lib/core/CHIPError.h>
-
-namespace chip {
-namespace app {
-namespace reporting {
-namespace DataModelImpl {
-
-DataModel::ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataModel,
-                                                  const Access::SubjectDescriptor & subjectDescriptor, bool isFabricFiltered,
-                                                  AttributeReportIBs::Builder & reportBuilder,
-                                                  const ConcreteReadAttributePath & path, AttributeEncodeState * encoderState);
-
-bool IsClusterDataVersionEqualTo(DataModel::Provider * dataModel, const ConcreteClusterPath & path, DataVersion dataVersion);
-
-} // namespace DataModelImpl
-} // namespace reporting
-} // namespace app
-} // namespace chip
diff --git a/src/app/reporting/Read-Ember.cpp b/src/app/reporting/Read-Ember.cpp
deleted file mode 100644
index e07df08..0000000
--- a/src/app/reporting/Read-Ember.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *    Copyright (c) 2024 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-#include <app/reporting/Read-Ember.h>
-
-#include <app/AppConfig.h>
-#include <app/data-model-provider/ActionReturnStatus.h>
-#include <app/util/MatterCallbacks.h>
-#include <app/util/ember-compatibility-functions.h>
-
-namespace chip {
-namespace app {
-namespace reporting {
-namespace EmberImpl {
-
-DataModel::ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataModel,
-                                                  const Access::SubjectDescriptor & subjectDescriptor, bool isFabricFiltered,
-                                                  AttributeReportIBs::Builder & reportBuilder,
-                                                  const ConcreteReadAttributePath & path, AttributeEncodeState * encoderState)
-{
-    // Odd ifdef is to only do this if the `Read-Check` does not do it already.
-#if !CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-    ChipLogDetail(DataManagement, "<RE:Run> Cluster %" PRIx32 ", Attribute %" PRIx32 " is dirty", path.mClusterId,
-                  path.mAttributeId);
-
-    DataModelCallbacks::GetInstance()->AttributeOperation(DataModelCallbacks::OperationType::Read,
-                                                          DataModelCallbacks::OperationOrder::Pre, path);
-#endif // !CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-
-    ReturnErrorOnFailure(ReadSingleClusterData(subjectDescriptor, isFabricFiltered, path, reportBuilder, encoderState));
-
-    // Odd ifdef is to only do this if the `Read-Check` does not do it already.
-#if !CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-    DataModelCallbacks::GetInstance()->AttributeOperation(DataModelCallbacks::OperationType::Read,
-                                                          DataModelCallbacks::OperationOrder::Post, path);
-#endif // !CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-
-    return CHIP_NO_ERROR;
-}
-
-bool IsClusterDataVersionEqualTo(DataModel::Provider * dataModel, const ConcreteClusterPath & path, DataVersion dataVersion)
-{
-    return IsClusterDataVersionEqual(path, dataVersion);
-}
-
-} // namespace EmberImpl
-} // namespace reporting
-} // namespace app
-} // namespace chip
diff --git a/src/app/reporting/Read-Ember.h b/src/app/reporting/Read-Ember.h
deleted file mode 100644
index 4aaf2f1..0000000
--- a/src/app/reporting/Read-Ember.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *    Copyright (c) 2024 Project CHIP Authors
- *    All rights reserved.
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-#pragma once
-
-#include <access/SubjectDescriptor.h>
-#include <app/AttributeEncodeState.h>
-#include <app/ConcreteClusterPath.h>
-#include <app/MessageDef/AttributeReportIBs.h>
-#include <app/data-model-provider/ActionReturnStatus.h>
-#include <app/data-model-provider/Provider.h>
-#include <lib/core/CHIPError.h>
-#include <lib/core/DataModelTypes.h>
-
-namespace chip {
-namespace app {
-namespace reporting {
-namespace EmberImpl {
-
-DataModel::ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataModel,
-                                                  const Access::SubjectDescriptor & subjectDescriptor, bool isFabricFiltered,
-                                                  AttributeReportIBs::Builder & reportBuilder,
-                                                  const ConcreteReadAttributePath & path, AttributeEncodeState * encoderState);
-
-bool IsClusterDataVersionEqualTo(DataModel::Provider * dataModel, const ConcreteClusterPath & path, DataVersion dataVersion);
-
-} // namespace EmberImpl
-} // namespace reporting
-} // namespace app
-} // namespace chip
diff --git a/src/app/reporting/Read-DataModel.cpp b/src/app/reporting/Read.cpp
similarity index 92%
rename from src/app/reporting/Read-DataModel.cpp
rename to src/app/reporting/Read.cpp
index 584536b..db55b14 100644
--- a/src/app/reporting/Read-DataModel.cpp
+++ b/src/app/reporting/Read.cpp
@@ -14,7 +14,7 @@
  *    See the License for the specific language governing permissions and
  *    limitations under the License.
  */
-#include <app/reporting/Read-DataModel.h>
+#include <app/reporting/Read.h>
 
 #include <app/AppConfig.h>
 #include <app/data-model-provider/ActionReturnStatus.h>
@@ -26,20 +26,17 @@
 namespace chip {
 namespace app {
 namespace reporting {
-namespace DataModelImpl {
+namespace Impl {
 
 DataModel::ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataModel,
                                                   const Access::SubjectDescriptor & subjectDescriptor, bool isFabricFiltered,
                                                   AttributeReportIBs::Builder & reportBuilder,
                                                   const ConcreteReadAttributePath & path, AttributeEncodeState * encoderState)
 {
-    // Odd ifdef is to only do this if the `Read-Check` does not do it already.
-#if !CHIP_CONFIG_USE_EMBER_DATA_MODEL
     ChipLogDetail(DataManagement, "<RE:Run> Cluster %" PRIx32 ", Attribute %" PRIx32 " is dirty", path.mClusterId,
                   path.mAttributeId);
     DataModelCallbacks::GetInstance()->AttributeOperation(DataModelCallbacks::OperationType::Read,
                                                           DataModelCallbacks::OperationOrder::Pre, path);
-#endif // !CHIP_CONFIG_USE_EMBER_DATA_MODEL
 
     DataModel::ReadAttributeRequest readRequest;
 
@@ -70,7 +67,6 @@
     if (status.IsSuccess())
     {
         // Odd ifdef is to only do this if the `Read-Check` does not do it already.
-#if !CHIP_CONFIG_USE_EMBER_DATA_MODEL
         // TODO: this callback being only executed on success is awkward. The Write callback is always done
         //       for both read and write.
         //
@@ -78,7 +74,6 @@
         //       call this.
         DataModelCallbacks::GetInstance()->AttributeOperation(DataModelCallbacks::OperationType::Read,
                                                               DataModelCallbacks::OperationOrder::Post, path);
-#endif // !CHIP_CONFIG_USE_EMBER_DATA_MODEL
         return status;
     }
 
@@ -115,7 +110,7 @@
     return (info->dataVersion == dataVersion);
 }
 
-} // namespace DataModelImpl
+} // namespace Impl
 } // namespace reporting
 } // namespace app
 } // namespace chip
diff --git a/src/app/reporting/Read.h b/src/app/reporting/Read.h
index c568c53..6731add 100644
--- a/src/app/reporting/Read.h
+++ b/src/app/reporting/Read.h
@@ -16,31 +16,25 @@
  */
 #pragma once
 
-#include <app/AppConfig.h>
-
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL && CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-#include <app/reporting/Read-Checked.h>
-#else
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-#include <app/reporting/Read-DataModel.h>
-#else
-#include <app/reporting/Read-Ember.h>
-#endif // CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-#endif // CHIP_CONFIG_USE_EMBER_DATA_MODEL && CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
+#include <access/SubjectDescriptor.h>
+#include <app/AttributeEncodeState.h>
+#include <app/MessageDef/AttributeReportIBs.h>
+#include <app/data-model-provider/ActionReturnStatus.h>
+#include <app/data-model-provider/Provider.h>
+#include <lib/core/CHIPError.h>
 
 namespace chip {
 namespace app {
 namespace reporting {
+namespace Impl {
 
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL && CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-namespace Impl = CheckedImpl;
-#else
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-namespace Impl = DataModelImpl;
-#else
-namespace Impl = EmberImpl;
-#endif // CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-#endif // CHIP_CONFIG_USE_EMBER_DATA_MODEL && CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
+DataModel::ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataModel,
+                                                  const Access::SubjectDescriptor & subjectDescriptor, bool isFabricFiltered,
+                                                  AttributeReportIBs::Builder & reportBuilder,
+                                                  const ConcreteReadAttributePath & path, AttributeEncodeState * encoderState);
+
+bool IsClusterDataVersionEqualTo(DataModel::Provider * dataModel, const ConcreteClusterPath & path, DataVersion dataVersion);
+} // namespace Impl
 
 } // namespace reporting
 } // namespace app
diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp
index 9a32401..cfb8d21 100644
--- a/src/app/server/Server.cpp
+++ b/src/app/server/Server.cpp
@@ -26,7 +26,6 @@
 #include <app/server/Dnssd.h>
 #include <app/server/EchoHandler.h>
 #include <app/util/DataModelHandler.h>
-#include <app/util/ember-compatibility-functions.h>
 
 #if CONFIG_NETWORK_LAYER_BLE
 #include <ble/Ble.h>
@@ -83,7 +82,6 @@
 
 namespace {
 
-#if CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
 class DeviceTypeResolver : public chip::Access::AccessControl::DeviceTypeResolver
 {
 public:
@@ -95,30 +93,12 @@
         {
             if (type->deviceTypeId == deviceType)
             {
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
-                VerifyOrDie(chip::app::IsDeviceTypeOnEndpoint(deviceType, endpoint));
-#endif // CHIP_CONFIG_USE_EMBER_DATA_MODEL
                 return true;
             }
         }
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL
-        VerifyOrDie(!chip::app::IsDeviceTypeOnEndpoint(deviceType, endpoint));
-#endif // CHIP_CONFIG_USE_EMBER_DATA_MODEL
         return false;
     }
 } sDeviceTypeResolver;
-#else // CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-
-// Ember implementation of the device type resolver
-class DeviceTypeResolver : public chip::Access::AccessControl::DeviceTypeResolver
-{
-public:
-    bool IsDeviceTypeOnEndpoint(chip::DeviceTypeId deviceType, chip::EndpointId endpoint) override
-    {
-        return chip::app::IsDeviceTypeOnEndpoint(deviceType, endpoint);
-    }
-} sDeviceTypeResolver;
-#endif
 
 } // namespace
 
diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn
index 9ebed23..03dadc0 100644
--- a/src/app/tests/BUILD.gn
+++ b/src/app/tests/BUILD.gn
@@ -171,7 +171,7 @@
     "test-ember-api.cpp",
     "test-ember-api.h",
 
-    # The overrides in these files are overrides from ember-compatibility-functions
+    # The overrides in these files are overrides from ember generated code
     # and the data model interface is NOT aware of such functionality
     #
     # TODO: ideally tests should have been written via mock ember, however mock ember did
diff --git a/src/app/tests/TestCommandInteraction.cpp b/src/app/tests/TestCommandInteraction.cpp
index a44d76d..4535a51 100644
--- a/src/app/tests/TestCommandInteraction.cpp
+++ b/src/app/tests/TestCommandInteraction.cpp
@@ -193,7 +193,7 @@
     }
 };
 
-Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aRequestCommandPath)
+static Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aRequestCommandPath)
 {
     // Mock cluster catalog, only support commands on one cluster on one endpoint.
     if (aRequestCommandPath.mEndpointId != kTestEndpointId)
diff --git a/src/app/tests/integration/chip_im_initiator.cpp b/src/app/tests/integration/chip_im_initiator.cpp
index 48a66cb..70a18b8 100644
--- a/src/app/tests/integration/chip_im_initiator.cpp
+++ b/src/app/tests/integration/chip_im_initiator.cpp
@@ -617,11 +617,6 @@
 
 namespace chip {
 namespace app {
-Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath)
-{
-    // Always return success in test.
-    return Protocols::InteractionModel::Status::Success;
-}
 
 void DispatchSingleClusterCommand(const ConcreteCommandPath & aCommandPath, chip::TLV::TLVReader & aReader,
                                   CommandHandler * apCommandObj)
@@ -629,68 +624,6 @@
     // Nothing todo.
 }
 
-CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
-                                 const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
-                                 AttributeEncodeState * apEncoderState)
-{
-    AttributeReportIB::Builder & attributeReport = aAttributeReports.CreateAttributeReport();
-    ReturnErrorOnFailure(aAttributeReports.GetError());
-    AttributeStatusIB::Builder & attributeStatus = attributeReport.CreateAttributeStatus();
-    ReturnErrorOnFailure(attributeReport.GetError());
-    AttributePathIB::Builder & attributePath = attributeStatus.CreatePath();
-    ReturnErrorOnFailure(attributeStatus.GetError());
-    attributePath.Endpoint(aPath.mEndpointId).Cluster(aPath.mClusterId).Attribute(aPath.mAttributeId).EndOfAttributePathIB();
-    ReturnErrorOnFailure(attributePath.GetError());
-    StatusIB::Builder & errorStatus = attributeStatus.CreateErrorStatus();
-    errorStatus.EncodeStatusIB(StatusIB(Protocols::InteractionModel::Status::UnsupportedAttribute));
-    ReturnErrorOnFailure(errorStatus.GetError());
-    attributeStatus.EndOfAttributeStatusIB();
-    ReturnErrorOnFailure(attributeStatus.GetError());
-    return attributeReport.EndOfAttributeReportIB();
-}
-
-const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aConcreteClusterPath)
-{
-    // Note: This test does not make use of the real attribute metadata.
-    static EmberAfAttributeMetadata stub = { .defaultValue = EmberAfDefaultOrMinMaxAttributeValue(uint32_t(0)) };
-    return &stub;
-}
-
-bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath)
-{
-    return true;
-}
-
-Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath)
-{
-    return Protocols::InteractionModel::Status::Success;
-}
-
-CHIP_ERROR WriteSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath,
-                                  TLV::TLVReader & aReader, WriteHandler *)
-{
-    if (aPath.mClusterId != kTestClusterId || aPath.mEndpointId != kTestEndpointId)
-    {
-        return CHIP_ERROR_INVALID_ARGUMENT;
-    }
-
-    if (aReader.GetLength() != 0)
-    {
-        chip::TLV::Debug::Dump(aReader, TLVPrettyPrinter);
-    }
-    return CHIP_NO_ERROR;
-}
-
-bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion)
-{
-    return true;
-}
-
-bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint)
-{
-    return false;
-}
-
 } // namespace app
 } // namespace chip
 
diff --git a/src/app/tests/integration/chip_im_responder.cpp b/src/app/tests/integration/chip_im_responder.cpp
index b65710d..12996af 100644
--- a/src/app/tests/integration/chip_im_responder.cpp
+++ b/src/app/tests/integration/chip_im_responder.cpp
@@ -25,6 +25,7 @@
  */
 
 #include "MockEvents.h"
+#include "common.h"
 #include <app/AttributeValueEncoder.h>
 #include <app/CommandHandler.h>
 #include <app/CommandSender.h>
@@ -76,43 +77,13 @@
 //
 //   We cannot just say "every attribut exist, every device on every endpoint exists,
 //   every data version compare is the same etc.".
-//
-// The following override implementation need changing:
-//   - ServerClusterCommandExists - should have a proper data mmodel
-//   - ConcreteAttributePathExists - cannot say "Yes" on all paths when query for EP/Cluster would fail
-//   - CheckEventSupportStatus - cannot say yes for invalid endpoints/clusters
-//   - IsClusterDataVersionEqual returning true on everything is odd
-//   - IsDeviceTypeOnEndpoint returning true on every value seems odd
-
-Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath)
-{
-    // The Mock cluster catalog -- only have one command on one cluster on one endpoint.
-    using Protocols::InteractionModel::Status;
-
-    if (aCommandPath.mEndpointId != kTestEndpointId)
-    {
-        return Status::UnsupportedEndpoint;
-    }
-
-    if (aCommandPath.mClusterId != kTestClusterId)
-    {
-        return Status::UnsupportedCluster;
-    }
-
-    if (aCommandPath.mCommandId != kTestCommandId)
-    {
-        return Status::UnsupportedCommand;
-    }
-
-    return Status::Success;
-}
 
 void DispatchSingleClusterCommand(const ConcreteCommandPath & aRequestCommandPath, chip::TLV::TLVReader & aReader,
                                   CommandHandler * apCommandObj)
 {
     static bool statusCodeFlipper = false;
 
-    if (ServerClusterCommandExists(aRequestCommandPath) != Protocols::InteractionModel::Status::Success)
+    if (aRequestCommandPath != ConcreteCommandPath(kTestEndpointId, kTestClusterId, kTestCommandId))
     {
         return;
     }
@@ -144,49 +115,6 @@
     statusCodeFlipper = !statusCodeFlipper;
 }
 
-CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
-                                 const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
-                                 AttributeEncodeState * apEncoderState)
-{
-    return AttributeValueEncoder(aAttributeReports, aSubjectDescriptor, aPath, 0).Encode(kTestFieldValue1);
-}
-
-bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath)
-{
-    return true;
-}
-
-Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath)
-{
-    return Protocols::InteractionModel::Status::Success;
-}
-
-const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aConcreteClusterPath)
-{
-    // Note: This test does not make use of the real attribute metadata.
-    static EmberAfAttributeMetadata stub = { .defaultValue = EmberAfDefaultOrMinMaxAttributeValue(uint32_t(0)) };
-    return &stub;
-}
-
-CHIP_ERROR WriteSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath,
-                                  TLV::TLVReader & aReader, WriteHandler * apWriteHandler)
-{
-    CHIP_ERROR err = CHIP_NO_ERROR;
-    ConcreteDataAttributePath attributePath(2, 3, 4);
-    err = apWriteHandler->AddStatus(attributePath, Protocols::InteractionModel::Status::Success);
-    return err;
-}
-
-bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion)
-{
-    return true;
-}
-
-bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint)
-{
-    return false;
-}
-
 } // namespace app
 } // namespace chip
 
diff --git a/src/app/tests/test-interaction-model-api.cpp b/src/app/tests/test-interaction-model-api.cpp
index 33097d3..d263e25 100644
--- a/src/app/tests/test-interaction-model-api.cpp
+++ b/src/app/tests/test-interaction-model-api.cpp
@@ -60,78 +60,15 @@
     AttributeValueDecoder & mDecoder;
 };
 
-// Used by the code in TestWriteInteraction.cpp (and generally tests that interact with the WriteHandler may need this).
-const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aConcreteClusterPath)
-{
-    // Note: This test does not make use of the real attribute metadata.
-    static EmberAfAttributeMetadata stub = { .defaultValue = EmberAfDefaultOrMinMaxAttributeValue(uint32_t(0)) };
-    return &stub;
-}
-
-// Used by the code in TestWriteInteraction.cpp (and generally tests that interact with the WriteHandler may need this).
-CHIP_ERROR WriteSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath,
-                                  TLV::TLVReader & aReader, WriteHandler * aWriteHandler)
-{
-    if (aPath.mDataVersion.HasValue() && aPath.mDataVersion.Value() == Test::kRejectedDataVersion)
-    {
-        return aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::DataVersionMismatch);
-    }
-
-    TLV::TLVWriter writer;
-    writer.Init(chip::Test::attributeDataTLV);
-    writer.CopyElement(TLV::AnonymousTag(), aReader);
-    chip::Test::attributeDataTLVLen = writer.GetLengthWritten();
-    return aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success);
-}
-
-// Used by the code in TestAclAttribute.cpp (and generally tests that interact with the InteractionModelEngine may need this).
-bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath)
-{
-    return aPath.mClusterId != Test::kTestDeniedClusterId1;
-}
-
-// Used by the code in TestAclAttribute.cpp (and generally tests that interact with the InteractionModelEngine may need this).
-Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath)
-{
-    if (aPath.mClusterId == Test::kTestDeniedClusterId1)
-    {
-        return Protocols::InteractionModel::Status::UnsupportedCluster;
-    }
-
-    return Protocols::InteractionModel::Status::Success;
-}
-
-// strong defintion in TestCommandInteraction.cpp
-__attribute__((weak)) Protocols::InteractionModel::Status
-ServerClusterCommandExists(const ConcreteCommandPath & aRequestCommandPath)
-{
-    // Mock cluster catalog, only support commands on one cluster on one endpoint.
-    using Protocols::InteractionModel::Status;
-
-    return Status::Success;
-}
-
 // strong defintion in TestCommandInteraction.cpp
 __attribute__((weak)) void DispatchSingleClusterCommand(const ConcreteCommandPath & aRequestCommandPath,
                                                         chip::TLV::TLVReader & aReader, CommandHandler * apCommandObj)
 {}
 
 // Used by the code in TestReadInteraction.cpp (and generally tests that interact with the Reporting Engine may need this).
-bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion)
-{
-    return (Test::kTestDataVersion1 == aRequiredVersion);
-}
-
-// Used by the code in TestReadInteraction.cpp.
-bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint)
-{
-    return false;
-}
-
-// Used by the code in TestReadInteraction.cpp (and generally tests that interact with the Reporting Engine may need this).
-CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
-                                 const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
-                                 AttributeEncodeState * apEncoderState)
+static CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
+                                        const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
+                                        AttributeEncodeState * apEncoderState)
 {
     if (aPath.mClusterId >= Test::kMockEndpointMin)
     {
diff --git a/src/app/tests/test-interaction-model-api.h b/src/app/tests/test-interaction-model-api.h
index df410c6..0e0fd2c0 100644
--- a/src/app/tests/test-interaction-model-api.h
+++ b/src/app/tests/test-interaction-model-api.h
@@ -81,25 +81,11 @@
 } // namespace Test
 namespace app {
 
-CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
-                                 const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
-                                 AttributeEncodeState * apEncoderState);
-
 bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion);
 
-CHIP_ERROR WriteSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath,
-                                  TLV::TLVReader & aReader, WriteHandler * aWriteHandler);
-const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aConcreteClusterPath);
-
-Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath);
-
-Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aRequestCommandPath);
-
 void DispatchSingleClusterCommand(const ConcreteCommandPath & aRequestCommandPath, chip::TLV::TLVReader & aReader,
                                   CommandHandler * apCommandObj);
 
-bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint);
-
 /// A customized class for read/write/invoke that matches functionality
 /// with the ember-compatibility-functions functionality here.
 ///
diff --git a/src/app/util/ember-compatibility-functions.cpp b/src/app/util/ember-compatibility-functions.cpp
deleted file mode 100644
index e50b559..0000000
--- a/src/app/util/ember-compatibility-functions.cpp
+++ /dev/null
@@ -1,814 +0,0 @@
-/*
- *
- *    Copyright (c) 2021-2023 Project CHIP Authors
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-#include <app/util/ember-compatibility-functions.h>
-
-#include <access/AccessControl.h>
-#include <app/AttributeAccessInterfaceRegistry.h>
-#include <app/CommandHandlerInterface.h>
-#include <app/CommandHandlerInterfaceRegistry.h>
-#include <app/ConcreteAttributePath.h>
-#include <app/ConcreteEventPath.h>
-#include <app/GlobalAttributes.h>
-#include <app/InteractionModelEngine.h>
-#include <app/RequiredPrivilege.h>
-#include <app/reporting/Engine.h>
-#include <app/reporting/reporting.h>
-#include <app/util/att-storage.h>
-#include <app/util/attribute-storage-detail.h>
-#include <app/util/attribute-storage-null-handling.h>
-#include <app/util/attribute-storage.h>
-#include <app/util/attribute-table-detail.h>
-#include <app/util/attribute-table.h>
-#include <app/util/config.h>
-#include <app/util/ember-global-attribute-access-interface.h>
-#include <app/util/ember-io-storage.h>
-#include <app/util/odd-sized-integers.h>
-#include <app/util/util.h>
-#include <lib/core/CHIPCore.h>
-#include <lib/core/TLV.h>
-#include <lib/support/CodeUtils.h>
-#include <lib/support/SafeInt.h>
-#include <lib/support/TypeTraits.h>
-#include <platform/LockTracker.h>
-#include <protocols/interaction_model/Constants.h>
-
-#include <app-common/zap-generated/attribute-type.h>
-
-#include <zap-generated/endpoint_config.h>
-
-#include <limits>
-
-using chip::Protocols::InteractionModel::Status;
-
-using namespace chip;
-using namespace chip::app;
-using namespace chip::Access;
-using namespace chip::app::Compatibility;
-using namespace chip::app::Compatibility::Internal;
-
-namespace chip {
-namespace app {
-namespace {
-
-template <typename T>
-CHIP_ERROR attributeBufferToNumericTlvData(TLV::TLVWriter & writer, bool isNullable)
-{
-    typename NumericAttributeTraits<T>::StorageType value;
-    memcpy(&value, gEmberAttributeIOBufferSpan.data(), sizeof(value));
-    TLV::Tag tag = TLV::ContextTag(AttributeDataIB::Tag::kData);
-    if (isNullable && NumericAttributeTraits<T>::IsNullValue(value))
-    {
-        return writer.PutNull(tag);
-    }
-
-    if (!NumericAttributeTraits<T>::CanRepresentValue(isNullable, value))
-    {
-        return CHIP_ERROR_INCORRECT_STATE;
-    }
-
-    return NumericAttributeTraits<T>::Encode(writer, tag, value);
-}
-
-} // anonymous namespace
-
-Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath)
-{
-    using Protocols::InteractionModel::Status;
-
-    const EmberAfEndpointType * type = emberAfFindEndpointType(aCommandPath.mEndpointId);
-    if (type == nullptr)
-    {
-        return Status::UnsupportedEndpoint;
-    }
-
-    const EmberAfCluster * cluster = emberAfFindClusterInType(type, aCommandPath.mClusterId, CLUSTER_MASK_SERVER);
-    if (cluster == nullptr)
-    {
-        return Status::UnsupportedCluster;
-    }
-
-    auto * commandHandler =
-        CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(aCommandPath.mEndpointId, aCommandPath.mClusterId);
-    if (commandHandler)
-    {
-        struct Context
-        {
-            bool commandExists;
-            CommandId targetCommand;
-        } context{ false, aCommandPath.mCommandId };
-
-        CHIP_ERROR err = commandHandler->EnumerateAcceptedCommands(
-            aCommandPath,
-            [](CommandId command, void * closure) -> Loop {
-                auto * ctx = static_cast<Context *>(closure);
-                if (ctx->targetCommand == command)
-                {
-                    ctx->commandExists = true;
-                    return Loop::Break;
-                }
-                return Loop::Continue;
-            },
-            &context);
-
-        // We now have three cases:
-        // 1) handler returned CHIP_ERROR_NOT_IMPLEMENTED.  In that case we
-        //    should fall back to looking at cluster->acceptedCommandList
-        // 2) handler returned success.  In that case, the handler is the source
-        //    of truth about the set of accepted commands, and
-        //    context.commandExists indicates whether a aCommandPath.mCommandId
-        //    was in the set, and we should return either Success or
-        //    UnsupportedCommand accordingly.
-        // 3) Some other status was returned.  In this case we should probably
-        //    err on the side of not allowing the command, since we have no idea
-        //    whether to allow it or not.
-        if (err != CHIP_ERROR_NOT_IMPLEMENTED)
-        {
-            if (err == CHIP_NO_ERROR)
-            {
-                return context.commandExists ? Status::Success : Status::UnsupportedCommand;
-            }
-
-            return Status::Failure;
-        }
-    }
-
-    for (const CommandId * cmd = cluster->acceptedCommandList; cmd != nullptr && *cmd != kInvalidCommandId; cmd++)
-    {
-        if (*cmd == aCommandPath.mCommandId)
-        {
-            return Status::Success;
-        }
-    }
-
-    return Status::UnsupportedCommand;
-}
-
-namespace {
-
-CHIP_ERROR ReadClusterDataVersion(const ConcreteClusterPath & aConcreteClusterPath, DataVersion & aDataVersion)
-{
-    DataVersion * version = emberAfDataVersionStorage(aConcreteClusterPath);
-    if (version == nullptr)
-    {
-        ChipLogError(DataManagement, "Endpoint %x, Cluster " ChipLogFormatMEI " not found in ReadClusterDataVersion!",
-                     aConcreteClusterPath.mEndpointId, ChipLogValueMEI(aConcreteClusterPath.mClusterId));
-        return CHIP_ERROR_NOT_FOUND;
-    }
-    aDataVersion = *version;
-    return CHIP_NO_ERROR;
-}
-
-// Helper function for trying to read an attribute value via an
-// AttributeAccessInterface.  On failure, the read has failed.  On success, the
-// aTriedEncode outparam is set to whether the AttributeAccessInterface tried to encode a value.
-CHIP_ERROR ReadViaAccessInterface(const SubjectDescriptor & subjectDescriptor, bool aIsFabricFiltered,
-                                  const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
-                                  AttributeEncodeState * aEncoderState, AttributeAccessInterface * aAccessInterface,
-                                  bool * aTriedEncode)
-{
-    AttributeEncodeState state(aEncoderState);
-    DataVersion version = 0;
-    ReturnErrorOnFailure(ReadClusterDataVersion(aPath, version));
-    AttributeValueEncoder valueEncoder(aAttributeReports, subjectDescriptor, aPath, version, aIsFabricFiltered, state);
-    CHIP_ERROR err = aAccessInterface->Read(aPath, valueEncoder);
-
-    if (err == CHIP_IM_GLOBAL_STATUS(UnsupportedRead) && aPath.mExpanded)
-    {
-        //
-        // Set this to true to ensure our caller will return immediately without proceeding further.
-        //
-        *aTriedEncode = true;
-        return CHIP_NO_ERROR;
-    }
-
-    if (err != CHIP_NO_ERROR)
-    {
-        // If the err is not CHIP_NO_ERROR, means the encoding was aborted, then the valueEncoder may save its state.
-        // The state is used by list chunking feature for now.
-        if (aEncoderState != nullptr)
-        {
-            *aEncoderState = valueEncoder.GetState();
-        }
-        return err;
-    }
-
-    *aTriedEncode = valueEncoder.TriedEncode();
-    return CHIP_NO_ERROR;
-}
-
-// Determine the appropriate status response for an unsupported attribute for
-// the given path.  Must be called when the attribute is known to be unsupported
-// (i.e. we found no attribute metadata for it).
-Protocols::InteractionModel::Status UnsupportedAttributeStatus(const ConcreteAttributePath & aPath)
-{
-    using Protocols::InteractionModel::Status;
-
-    const EmberAfEndpointType * type = emberAfFindEndpointType(aPath.mEndpointId);
-    if (type == nullptr)
-    {
-        return Status::UnsupportedEndpoint;
-    }
-
-    const EmberAfCluster * cluster = emberAfFindClusterInType(type, aPath.mClusterId, CLUSTER_MASK_SERVER);
-    if (cluster == nullptr)
-    {
-        return Status::UnsupportedCluster;
-    }
-
-    // Since we know the attribute is unsupported and the endpoint/cluster are
-    // OK, this is the only option left.
-    return Status::UnsupportedAttribute;
-}
-
-// Will set at most one of the out-params (aAttributeCluster or
-// aAttributeMetadata) to non-null.  Both null means attribute not supported,
-// aAttributeCluster non-null means this is a supported global attribute that
-// does not have metadata.
-void FindAttributeMetadata(const ConcreteAttributePath & aPath, const EmberAfCluster ** aAttributeCluster,
-                           const EmberAfAttributeMetadata ** aAttributeMetadata)
-{
-    *aAttributeCluster  = nullptr;
-    *aAttributeMetadata = nullptr;
-
-    for (auto & attr : GlobalAttributesNotInMetadata)
-    {
-        if (attr == aPath.mAttributeId)
-        {
-            *aAttributeCluster = emberAfFindServerCluster(aPath.mEndpointId, aPath.mClusterId);
-            return;
-        }
-    }
-
-    *aAttributeMetadata = emberAfLocateAttributeMetadata(aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId);
-}
-
-} // anonymous namespace
-
-bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath)
-{
-    for (auto & attr : GlobalAttributesNotInMetadata)
-    {
-        if (attr == aPath.mAttributeId)
-        {
-            return (emberAfFindServerCluster(aPath.mEndpointId, aPath.mClusterId) != nullptr);
-        }
-    }
-    return (emberAfLocateAttributeMetadata(aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId) != nullptr);
-}
-
-CHIP_ERROR ReadSingleClusterData(const SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
-                                 const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
-                                 AttributeEncodeState * apEncoderState)
-{
-    ChipLogDetail(DataManagement,
-                  "Reading attribute: Cluster=" ChipLogFormatMEI " Endpoint=%x AttributeId=" ChipLogFormatMEI " (expanded=%d)",
-                  ChipLogValueMEI(aPath.mClusterId), aPath.mEndpointId, ChipLogValueMEI(aPath.mAttributeId), aPath.mExpanded);
-
-    // Check attribute existence. This includes attributes with registered metadata, but also specially handled
-    // mandatory global attributes (which just check for cluster on endpoint).
-
-    const EmberAfCluster * attributeCluster            = nullptr;
-    const EmberAfAttributeMetadata * attributeMetadata = nullptr;
-    FindAttributeMetadata(aPath, &attributeCluster, &attributeMetadata);
-
-    if (attributeCluster == nullptr && attributeMetadata == nullptr)
-    {
-        return CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(UnsupportedAttributeStatus(aPath));
-    }
-
-    // Check access control. A failed check will disallow the operation, and may or may not generate an attribute report
-    // depending on whether the path was expanded.
-
-    {
-        Access::RequestPath requestPath{ .cluster     = aPath.mClusterId,
-                                         .endpoint    = aPath.mEndpointId,
-                                         .requestType = Access::RequestType::kAttributeReadRequest,
-                                         .entityId    = aPath.mAttributeId };
-        Access::Privilege requestPrivilege = RequiredPrivilege::ForReadAttribute(aPath);
-        CHIP_ERROR err                     = Access::GetAccessControl().Check(aSubjectDescriptor, requestPath, requestPrivilege);
-        if (err != CHIP_NO_ERROR)
-        {
-            VerifyOrReturnError((err == CHIP_ERROR_ACCESS_DENIED) || (err == CHIP_ERROR_ACCESS_RESTRICTED_BY_ARL), err);
-            if (aPath.mExpanded)
-            {
-                return CHIP_NO_ERROR;
-            }
-            return err == CHIP_ERROR_ACCESS_DENIED ? CHIP_IM_GLOBAL_STATUS(UnsupportedAccess)
-                                                   : CHIP_IM_GLOBAL_STATUS(AccessRestricted);
-        }
-    }
-
-    {
-        // Special handling for mandatory global attributes: these are always for attribute list, using a special
-        // reader (which can be lightweight constructed even from nullptr).
-        GlobalAttributeReader reader(attributeCluster);
-        AttributeAccessInterface * attributeOverride = (attributeCluster != nullptr)
-            ? &reader
-            : AttributeAccessInterfaceRegistry::Instance().Get(aPath.mEndpointId, aPath.mClusterId);
-        if (attributeOverride)
-        {
-            bool triedEncode = false;
-            ReturnErrorOnFailure(ReadViaAccessInterface(aSubjectDescriptor, aIsFabricFiltered, aPath, aAttributeReports,
-                                                        apEncoderState, attributeOverride, &triedEncode));
-            VerifyOrReturnError(!triedEncode, CHIP_NO_ERROR);
-        }
-    }
-
-    // Read attribute using Ember, if it doesn't have an override.
-
-    EmberAfAttributeSearchRecord record;
-    record.endpoint    = aPath.mEndpointId;
-    record.clusterId   = aPath.mClusterId;
-    record.attributeId = aPath.mAttributeId;
-    Status status      = emAfReadOrWriteAttribute(&record, &attributeMetadata, gEmberAttributeIOBufferSpan.data(),
-                                                  static_cast<uint16_t>(gEmberAttributeIOBufferSpan.size()),
-                                                  /* write = */ false);
-
-    if (status != Status::Success)
-    {
-        return CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(status);
-    }
-
-    // data available, return the corresponding record
-    AttributeReportIB::Builder & attributeReport = aAttributeReports.CreateAttributeReport();
-    ReturnErrorOnFailure(aAttributeReports.GetError());
-
-    AttributeDataIB::Builder & attributeDataIBBuilder = attributeReport.CreateAttributeData();
-    ReturnErrorOnFailure(attributeDataIBBuilder.GetError());
-
-    DataVersion version = 0;
-    ReturnErrorOnFailure(ReadClusterDataVersion(aPath, version));
-    attributeDataIBBuilder.DataVersion(version);
-    ReturnErrorOnFailure(attributeDataIBBuilder.GetError());
-
-    AttributePathIB::Builder & attributePathIBBuilder = attributeDataIBBuilder.CreatePath();
-    ReturnErrorOnFailure(attributeDataIBBuilder.GetError());
-
-    CHIP_ERROR err = attributePathIBBuilder.Endpoint(aPath.mEndpointId)
-                         .Cluster(aPath.mClusterId)
-                         .Attribute(aPath.mAttributeId)
-                         .EndOfAttributePathIB();
-    ReturnErrorOnFailure(err);
-
-    TLV::TLVWriter * writer = attributeDataIBBuilder.GetWriter();
-    VerifyOrReturnError(writer != nullptr, CHIP_NO_ERROR);
-
-    const EmberAfAttributeType attributeType = attributeMetadata->attributeType;
-    const bool isNullable                    = attributeMetadata->IsNullable();
-    const TLV::Tag tag                       = TLV::ContextTag(AttributeDataIB::Tag::kData);
-
-    switch (AttributeBaseType(attributeType))
-    {
-    case ZCL_NO_DATA_ATTRIBUTE_TYPE: // No data
-        ReturnErrorOnFailure(writer->PutNull(tag));
-        break;
-    case ZCL_BOOLEAN_ATTRIBUTE_TYPE: // Boolean
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<bool>(*writer, isNullable));
-        break;
-    case ZCL_INT8U_ATTRIBUTE_TYPE: // Unsigned 8-bit integer
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<uint8_t>(*writer, isNullable));
-        break;
-    case ZCL_INT16U_ATTRIBUTE_TYPE: // Unsigned 16-bit integer
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<uint16_t>(*writer, isNullable));
-        break;
-    case ZCL_INT24U_ATTRIBUTE_TYPE: // Unsigned 24-bit integer
-    {
-        using IntType = OddSizedInteger<3, false>;
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<IntType>(*writer, isNullable));
-        break;
-    }
-    case ZCL_INT32U_ATTRIBUTE_TYPE: // Unsigned 32-bit integer
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<uint32_t>(*writer, isNullable));
-        break;
-    case ZCL_INT40U_ATTRIBUTE_TYPE: // Unsigned 40-bit integer
-    {
-        using IntType = OddSizedInteger<5, false>;
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<IntType>(*writer, isNullable));
-        break;
-    }
-    case ZCL_INT48U_ATTRIBUTE_TYPE: // Unsigned 48-bit integer
-    {
-        using IntType = OddSizedInteger<6, false>;
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<IntType>(*writer, isNullable));
-        break;
-    }
-    case ZCL_INT56U_ATTRIBUTE_TYPE: // Unsigned 56-bit integer
-    {
-        using IntType = OddSizedInteger<7, false>;
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<IntType>(*writer, isNullable));
-        break;
-    }
-    case ZCL_INT64U_ATTRIBUTE_TYPE: // Unsigned 64-bit integer
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<uint64_t>(*writer, isNullable));
-        break;
-    case ZCL_INT8S_ATTRIBUTE_TYPE: // Signed 8-bit integer
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<int8_t>(*writer, isNullable));
-        break;
-    case ZCL_INT16S_ATTRIBUTE_TYPE: // Signed 16-bit integer
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<int16_t>(*writer, isNullable));
-        break;
-    case ZCL_INT24S_ATTRIBUTE_TYPE: // Signed 24-bit integer
-    {
-        using IntType = OddSizedInteger<3, true>;
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<IntType>(*writer, isNullable));
-        break;
-    }
-    case ZCL_INT32S_ATTRIBUTE_TYPE: // Signed 32-bit integer
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<int32_t>(*writer, isNullable));
-        break;
-    case ZCL_INT40S_ATTRIBUTE_TYPE: // Signed 40-bit integer
-    {
-        using IntType = OddSizedInteger<5, true>;
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<IntType>(*writer, isNullable));
-        break;
-    }
-    case ZCL_INT48S_ATTRIBUTE_TYPE: // Signed 48-bit integer
-    {
-        using IntType = OddSizedInteger<6, true>;
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<IntType>(*writer, isNullable));
-        break;
-    }
-    case ZCL_INT56S_ATTRIBUTE_TYPE: // Signed 56-bit integer
-    {
-        using IntType = OddSizedInteger<7, true>;
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<IntType>(*writer, isNullable));
-        break;
-    }
-    case ZCL_INT64S_ATTRIBUTE_TYPE: // Signed 64-bit integer
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<int64_t>(*writer, isNullable));
-        break;
-    case ZCL_SINGLE_ATTRIBUTE_TYPE: // 32-bit float
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<float>(*writer, isNullable));
-        break;
-    case ZCL_DOUBLE_ATTRIBUTE_TYPE: // 64-bit float
-        ReturnErrorOnFailure(attributeBufferToNumericTlvData<double>(*writer, isNullable));
-        break;
-    case ZCL_CHAR_STRING_ATTRIBUTE_TYPE: // Char string
-    {
-        char * actualData  = reinterpret_cast<char *>(gEmberAttributeIOBufferSpan.data() + 1);
-        uint8_t dataLength = gEmberAttributeIOBufferSpan[0];
-        if (dataLength == 0xFF)
-        {
-            VerifyOrReturnError(isNullable, CHIP_ERROR_INCORRECT_STATE);
-            ReturnErrorOnFailure(writer->PutNull(tag));
-        }
-        else
-        {
-            ReturnErrorOnFailure(writer->PutString(tag, actualData, dataLength));
-        }
-        break;
-    }
-    case ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE: {
-        char * actualData =
-            reinterpret_cast<char *>(gEmberAttributeIOBufferSpan.data() + 2); // The pascal string contains 2 bytes length
-        uint16_t dataLength;
-        memcpy(&dataLength, gEmberAttributeIOBufferSpan.data(), sizeof(dataLength));
-        if (dataLength == 0xFFFF)
-        {
-            VerifyOrReturnError(isNullable, CHIP_ERROR_INCORRECT_STATE);
-            ReturnErrorOnFailure(writer->PutNull(tag));
-        }
-        else
-        {
-            ReturnErrorOnFailure(writer->PutString(tag, actualData, dataLength));
-        }
-        break;
-    }
-    case ZCL_OCTET_STRING_ATTRIBUTE_TYPE: // Octet string
-    {
-        uint8_t * actualData = gEmberAttributeIOBufferSpan.data() + 1;
-        uint8_t dataLength   = gEmberAttributeIOBufferSpan[0];
-        if (dataLength == 0xFF)
-        {
-            VerifyOrReturnError(isNullable, CHIP_ERROR_INCORRECT_STATE);
-            ReturnErrorOnFailure(writer->PutNull(tag));
-        }
-        else
-        {
-            ReturnErrorOnFailure(writer->Put(tag, chip::ByteSpan(actualData, dataLength)));
-        }
-        break;
-    }
-    case ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE: {
-        uint8_t * actualData = gEmberAttributeIOBufferSpan.data() + 2; // The pascal string contains 2 bytes length
-        uint16_t dataLength;
-        memcpy(&dataLength, gEmberAttributeIOBufferSpan.data(), sizeof(dataLength));
-        if (dataLength == 0xFFFF)
-        {
-            VerifyOrReturnError(isNullable, CHIP_ERROR_INCORRECT_STATE);
-            ReturnErrorOnFailure(writer->PutNull(tag));
-        }
-        else
-        {
-            ReturnErrorOnFailure(writer->Put(tag, chip::ByteSpan(actualData, dataLength)));
-        }
-        break;
-    }
-    default:
-        ChipLogError(DataManagement, "Attribute type 0x%x not handled", static_cast<int>(attributeType));
-        return CHIP_IM_GLOBAL_STATUS(Failure);
-    }
-
-    // If we got this far, placing the data to be read in the output TLVWriter succeeded.
-    // Try to terminate our attribute report to signal success.
-    ReturnErrorOnFailure(attributeDataIBBuilder.EndOfAttributeDataIB());
-    return attributeReport.EndOfAttributeReportIB();
-}
-
-namespace {
-
-template <typename T>
-CHIP_ERROR numericTlvDataToAttributeBuffer(TLV::TLVReader & aReader, bool isNullable, uint16_t & dataLen)
-{
-    typename NumericAttributeTraits<T>::StorageType value;
-    VerifyOrDie(sizeof(value) <= gEmberAttributeIOBufferSpan.size());
-
-    if (isNullable && aReader.GetType() == TLV::kTLVType_Null)
-    {
-        NumericAttributeTraits<T>::SetNull(value);
-    }
-    else
-    {
-        typename NumericAttributeTraits<T>::WorkingType val;
-        ReturnErrorOnFailure(aReader.Get(val));
-        VerifyOrReturnError(NumericAttributeTraits<T>::CanRepresentValue(isNullable, val), CHIP_ERROR_INVALID_ARGUMENT);
-        NumericAttributeTraits<T>::WorkingToStorage(val, value);
-    }
-    dataLen = sizeof(value);
-    memcpy(gEmberAttributeIOBufferSpan.data(), &value, sizeof(value));
-    return CHIP_NO_ERROR;
-}
-
-template <typename T>
-CHIP_ERROR stringTlvDataToAttributeBuffer(TLV::TLVReader & aReader, bool isOctetString, bool isNullable, uint16_t & dataLen)
-{
-    const uint8_t * data = nullptr;
-    T len;
-    if (isNullable && aReader.GetType() == TLV::kTLVType_Null)
-    {
-        // Null is represented by an 0xFF or 0xFFFF length, respectively.
-        len = std::numeric_limits<T>::max();
-        memcpy(gEmberAttributeIOBufferSpan.data(), &len, sizeof(len));
-        dataLen = sizeof(len);
-    }
-    else
-    {
-        VerifyOrReturnError((isOctetString && aReader.GetType() == TLV::TLVType::kTLVType_ByteString) ||
-                                (!isOctetString && aReader.GetType() == TLV::TLVType::kTLVType_UTF8String),
-                            CHIP_ERROR_INVALID_ARGUMENT);
-        VerifyOrReturnError(CanCastTo<T>(aReader.GetLength()), CHIP_ERROR_MESSAGE_TOO_LONG);
-        ReturnErrorOnFailure(aReader.GetDataPtr(data));
-        len = static_cast<T>(aReader.GetLength());
-        VerifyOrReturnError(len != std::numeric_limits<T>::max(), CHIP_ERROR_MESSAGE_TOO_LONG);
-        VerifyOrReturnError(len + sizeof(len) /* length at the beginning of data */ <= gEmberAttributeIOBufferSpan.size(),
-                            CHIP_ERROR_MESSAGE_TOO_LONG);
-        memcpy(gEmberAttributeIOBufferSpan.data(), &len, sizeof(len));
-        memcpy(gEmberAttributeIOBufferSpan.data() + sizeof(len), data, len);
-        dataLen = static_cast<uint16_t>(len + sizeof(len));
-    }
-    return CHIP_NO_ERROR;
-}
-
-CHIP_ERROR prepareWriteData(const EmberAfAttributeMetadata * attributeMetadata, TLV::TLVReader & aReader, uint16_t & dataLen)
-{
-    EmberAfAttributeType expectedType = AttributeBaseType(attributeMetadata->attributeType);
-    bool isNullable                   = attributeMetadata->IsNullable();
-    switch (expectedType)
-    {
-    case ZCL_BOOLEAN_ATTRIBUTE_TYPE: // Boolean
-        return numericTlvDataToAttributeBuffer<bool>(aReader, isNullable, dataLen);
-    case ZCL_INT8U_ATTRIBUTE_TYPE: // Unsigned 8-bit integer
-        return numericTlvDataToAttributeBuffer<uint8_t>(aReader, isNullable, dataLen);
-    case ZCL_INT16U_ATTRIBUTE_TYPE: // Unsigned 16-bit integer
-        return numericTlvDataToAttributeBuffer<uint16_t>(aReader, isNullable, dataLen);
-    case ZCL_INT24U_ATTRIBUTE_TYPE: // Unsigned 24-bit integer
-    {
-        using IntType = OddSizedInteger<3, false>;
-        return numericTlvDataToAttributeBuffer<IntType>(aReader, isNullable, dataLen);
-    }
-    case ZCL_INT32U_ATTRIBUTE_TYPE: // Unsigned 32-bit integer
-        return numericTlvDataToAttributeBuffer<uint32_t>(aReader, isNullable, dataLen);
-    case ZCL_INT40U_ATTRIBUTE_TYPE: // Unsigned 40-bit integer
-    {
-        using IntType = OddSizedInteger<5, false>;
-        return numericTlvDataToAttributeBuffer<IntType>(aReader, isNullable, dataLen);
-    }
-    case ZCL_INT48U_ATTRIBUTE_TYPE: // Unsigned 48-bit integer
-    {
-        using IntType = OddSizedInteger<6, false>;
-        return numericTlvDataToAttributeBuffer<IntType>(aReader, isNullable, dataLen);
-    }
-    case ZCL_INT56U_ATTRIBUTE_TYPE: // Unsigned 56-bit integer
-    {
-        using IntType = OddSizedInteger<7, false>;
-        return numericTlvDataToAttributeBuffer<IntType>(aReader, isNullable, dataLen);
-    }
-    case ZCL_INT64U_ATTRIBUTE_TYPE: // Unsigned 64-bit integer
-        return numericTlvDataToAttributeBuffer<uint64_t>(aReader, isNullable, dataLen);
-    case ZCL_INT8S_ATTRIBUTE_TYPE: // Signed 8-bit integer
-        return numericTlvDataToAttributeBuffer<int8_t>(aReader, isNullable, dataLen);
-    case ZCL_INT16S_ATTRIBUTE_TYPE: // Signed 16-bit integer
-        return numericTlvDataToAttributeBuffer<int16_t>(aReader, isNullable, dataLen);
-    case ZCL_INT24S_ATTRIBUTE_TYPE: // Signed 24-bit integer
-    {
-        using IntType = OddSizedInteger<3, true>;
-        return numericTlvDataToAttributeBuffer<IntType>(aReader, isNullable, dataLen);
-    }
-    case ZCL_INT32S_ATTRIBUTE_TYPE: // Signed 32-bit integer
-        return numericTlvDataToAttributeBuffer<int32_t>(aReader, isNullable, dataLen);
-    case ZCL_INT40S_ATTRIBUTE_TYPE: // Signed 40-bit integer
-    {
-        using IntType = OddSizedInteger<5, true>;
-        return numericTlvDataToAttributeBuffer<IntType>(aReader, isNullable, dataLen);
-    }
-    case ZCL_INT48S_ATTRIBUTE_TYPE: // Signed 48-bit integer
-    {
-        using IntType = OddSizedInteger<6, true>;
-        return numericTlvDataToAttributeBuffer<IntType>(aReader, isNullable, dataLen);
-    }
-    case ZCL_INT56S_ATTRIBUTE_TYPE: // Signed 56-bit integer
-    {
-        using IntType = OddSizedInteger<7, true>;
-        return numericTlvDataToAttributeBuffer<IntType>(aReader, isNullable, dataLen);
-    }
-    case ZCL_INT64S_ATTRIBUTE_TYPE: // Signed 64-bit integer
-        return numericTlvDataToAttributeBuffer<int64_t>(aReader, isNullable, dataLen);
-    case ZCL_SINGLE_ATTRIBUTE_TYPE: // 32-bit float
-        return numericTlvDataToAttributeBuffer<float>(aReader, isNullable, dataLen);
-    case ZCL_DOUBLE_ATTRIBUTE_TYPE: // 64-bit float
-        return numericTlvDataToAttributeBuffer<double>(aReader, isNullable, dataLen);
-    case ZCL_OCTET_STRING_ATTRIBUTE_TYPE: // Octet string
-    case ZCL_CHAR_STRING_ATTRIBUTE_TYPE:  // Char string
-        return stringTlvDataToAttributeBuffer<uint8_t>(aReader, expectedType == ZCL_OCTET_STRING_ATTRIBUTE_TYPE, isNullable,
-                                                       dataLen);
-    case ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE: // Long octet string
-    case ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE:  // Long char string
-        return stringTlvDataToAttributeBuffer<uint16_t>(aReader, expectedType == ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE, isNullable,
-                                                        dataLen);
-    default:
-        ChipLogError(DataManagement, "Attribute type %x not handled", static_cast<int>(expectedType));
-        return CHIP_ERROR_INVALID_DATA_LIST;
-    }
-}
-} // namespace
-
-const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aPath)
-{
-    return emberAfLocateAttributeMetadata(aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId);
-}
-
-CHIP_ERROR WriteSingleClusterData(const SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath,
-                                  TLV::TLVReader & aReader, WriteHandler * apWriteHandler)
-{
-    // Check attribute existence. This includes attributes with registered metadata, but also specially handled
-    // mandatory global attributes (which just check for cluster on endpoint).
-    const EmberAfCluster * attributeCluster            = nullptr;
-    const EmberAfAttributeMetadata * attributeMetadata = nullptr;
-    FindAttributeMetadata(aPath, &attributeCluster, &attributeMetadata);
-
-    if (attributeCluster == nullptr && attributeMetadata == nullptr)
-    {
-        return apWriteHandler->AddStatus(aPath, UnsupportedAttributeStatus(aPath));
-    }
-
-    // All the global attributes we don't have metadata for are readonly.
-    if (attributeMetadata == nullptr || attributeMetadata->IsReadOnly())
-    {
-        return apWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::UnsupportedWrite);
-    }
-
-    {
-        Access::RequestPath requestPath{ .cluster     = aPath.mClusterId,
-                                         .endpoint    = aPath.mEndpointId,
-                                         .requestType = Access::RequestType::kAttributeWriteRequest,
-                                         .entityId    = aPath.mAttributeId };
-        Access::Privilege requestPrivilege = RequiredPrivilege::ForWriteAttribute(aPath);
-        CHIP_ERROR err                     = CHIP_NO_ERROR;
-        if (!apWriteHandler->ACLCheckCacheHit({ aPath, requestPrivilege }))
-        {
-            err = Access::GetAccessControl().Check(aSubjectDescriptor, requestPath, requestPrivilege);
-        }
-        if (err != CHIP_NO_ERROR)
-        {
-            VerifyOrReturnError((err == CHIP_ERROR_ACCESS_DENIED) || (err == CHIP_ERROR_ACCESS_RESTRICTED_BY_ARL), err);
-            // TODO: when wildcard/group writes are supported, handle them to discard rather than fail with status
-            return apWriteHandler->AddStatus(aPath,
-                                             err == CHIP_ERROR_ACCESS_DENIED
-                                                 ? Protocols::InteractionModel::Status::UnsupportedAccess
-                                                 : Protocols::InteractionModel::Status::AccessRestricted);
-        }
-        apWriteHandler->CacheACLCheckResult({ aPath, requestPrivilege });
-    }
-
-    if (attributeMetadata->MustUseTimedWrite() && !apWriteHandler->IsTimedWrite())
-    {
-        return apWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::NeedsTimedInteraction);
-    }
-
-    if (aPath.mDataVersion.HasValue() && !IsClusterDataVersionEqual(aPath, aPath.mDataVersion.Value()))
-    {
-        ChipLogError(DataManagement, "Write Version mismatch for Endpoint %x, Cluster " ChipLogFormatMEI, aPath.mEndpointId,
-                     ChipLogValueMEI(aPath.mClusterId));
-        return apWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::DataVersionMismatch);
-    }
-
-    if (auto * attrOverride = AttributeAccessInterfaceRegistry::Instance().Get(aPath.mEndpointId, aPath.mClusterId))
-    {
-        AttributeValueDecoder valueDecoder(aReader, aSubjectDescriptor);
-        ReturnErrorOnFailure(attrOverride->Write(aPath, valueDecoder));
-
-        if (valueDecoder.TriedDecode())
-        {
-            MatterReportingAttributeChangeCallback(aPath);
-            return apWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success);
-        }
-    }
-
-    CHIP_ERROR preparationError = CHIP_NO_ERROR;
-    uint16_t dataLen            = 0;
-    if ((preparationError = prepareWriteData(attributeMetadata, aReader, dataLen)) != CHIP_NO_ERROR)
-    {
-        ChipLogDetail(Zcl, "Failed to prepare data to write: %" CHIP_ERROR_FORMAT, preparationError.Format());
-        return apWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::InvalidValue);
-    }
-
-    if (dataLen > attributeMetadata->size)
-    {
-        ChipLogDetail(Zcl, "Data to write exceedes the attribute size claimed.");
-        return apWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::InvalidValue);
-    }
-
-    auto status = emAfWriteAttributeExternal(
-        aPath, EmberAfWriteDataInput(gEmberAttributeIOBufferSpan.data(), attributeMetadata->attributeType));
-    return apWriteHandler->AddStatus(aPath, status);
-}
-
-bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion)
-{
-    DataVersion * version = emberAfDataVersionStorage(aConcreteClusterPath);
-    if (version == nullptr)
-    {
-        ChipLogError(DataManagement, "Endpoint %x, Cluster " ChipLogFormatMEI " not found in IsClusterDataVersionEqual!",
-                     aConcreteClusterPath.mEndpointId, ChipLogValueMEI(aConcreteClusterPath.mClusterId));
-        return false;
-    }
-
-    return (*(version)) == aRequiredVersion;
-}
-
-bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint)
-{
-    CHIP_ERROR err;
-    auto deviceTypeList = emberAfDeviceTypeListFromEndpoint(endpoint, err);
-    if (err != CHIP_NO_ERROR)
-    {
-        return false;
-    }
-
-    for (auto & device : deviceTypeList)
-    {
-        if (device.deviceId == deviceType)
-        {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath)
-{
-    using Protocols::InteractionModel::Status;
-
-    const EmberAfEndpointType * type = emberAfFindEndpointType(aPath.mEndpointId);
-    if (type == nullptr)
-    {
-        return Status::UnsupportedEndpoint;
-    }
-
-    const EmberAfCluster * cluster = emberAfFindClusterInType(type, aPath.mClusterId, CLUSTER_MASK_SERVER);
-    if (cluster == nullptr)
-    {
-        return Status::UnsupportedCluster;
-    }
-
-    // No way to tell. Just claim supported.
-    return Status::Success;
-}
-
-} // namespace app
-} // namespace chip
diff --git a/src/app/util/ember-compatibility-functions.h b/src/app/util/ember-compatibility-functions.h
deleted file mode 100644
index ca7f169..0000000
--- a/src/app/util/ember-compatibility-functions.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- *    Copyright (c) 2024 Project CHIP Authors
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-#pragma once
-
-#include <access/SubjectDescriptor.h>
-#include <app/AttributeValueEncoder.h>
-#include <app/ConcreteAttributePath.h>
-#include <app/ConcreteCommandPath.h>
-#include <app/ConcreteEventPath.h>
-#include <app/WriteHandler.h>
-#include <app/util/attribute-metadata.h>
-#include <protocols/interaction_model/StatusCode.h>
-
-namespace chip {
-namespace app {
-
-/**
- *  Check whether the given cluster exists on the given endpoint and supports
- *  the given command.  If it does, Success will be returned.  If it does not,
- *  one of UnsupportedEndpoint, UnsupportedCluster, or UnsupportedCommand
- *  will be returned, depending on how the command fails to exist.
- */
-Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath);
-
-/**
- *  Check whether concrete attribute path is an "existent attribute path" in spec terms.
- *  @param[in]    aPath                 The concrete path of the data being read.
- *  @retval  boolean   true if the concrete attribute path indicates an attribute that exists on the node.
- */
-bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath);
-
-/**
- *  Fetch attribute value and version info and write to the AttributeReport provided.
- *  The ReadSingleClusterData will do everything required for encoding an attribute, i.e. it will try to put one or more
- * AttributeReportIB to the AttributeReportIBs::Builder.
- *  When the endpoint / cluster / attribute data specified by aPath does not exist, corresponding interaction
- * model error code will be put into aAttributeReports, and CHIP_NO_ERROR will be returned. If the data exists on the server, the
- * data (with tag kData) and the data version (with tag kDataVersion) will be put into aAttributeReports. TLVWriter error will be
- * returned if any error occurred while encoding these values. This function is implemented by CHIP as a part of cluster data
- * storage & management.
- *
- *  @param[in]    aSubjectDescriptor    The subject descriptor for the read.
- *  @param[in]    aPath                 The concrete path of the data being read.
- *  @param[in]    aAttributeReports      The TLV Builder for Cluter attribute builder.
- *
- *  @retval  CHIP_NO_ERROR on success
- */
-CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
-                                 const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
-                                 AttributeEncodeState * apEncoderState);
-
-/**
- * Returns the metadata of the attribute for the given path.
- *
- * @retval The metadata of the attribute, will return null if the given attribute does not exists.
- */
-const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aPath);
-
-/**
- * TODO: Document.
- */
-CHIP_ERROR WriteSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath,
-                                  TLV::TLVReader & aReader, WriteHandler * apWriteHandler);
-
-/**
- * Check if the given cluster has the given DataVersion.
- */
-bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion);
-
-/**
- * Returns true if device type is on endpoint, false otherwise.
- */
-bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint);
-
-/**
- * Returns the event support status for the given event, as an interaction model status.
- */
-Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath);
-
-} // namespace app
-} // namespace chip
diff --git a/src/controller/tests/data_model/DataModelFixtures.cpp b/src/controller/tests/data_model/DataModelFixtures.cpp
index f007275..6f42c38 100644
--- a/src/controller/tests/data_model/DataModelFixtures.cpp
+++ b/src/controller/tests/data_model/DataModelFixtures.cpp
@@ -85,9 +85,9 @@
 
 } // namespace DataModelTests
 
-CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
-                                 const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
-                                 AttributeEncodeState * apEncoderState)
+static CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered,
+                                        const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
+                                        AttributeEncodeState * apEncoderState)
 {
     if (aPath.mEndpointId >= chip::Test::kMockEndpointMin)
     {
@@ -224,175 +224,6 @@
     return CHIP_NO_ERROR;
 }
 
-bool IsClusterDataVersionEqual(const app::ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion)
-{
-    if (aRequiredVersion == kDataVersion)
-    {
-        return true;
-    }
-    if (Test::GetVersion() == aRequiredVersion)
-    {
-        return true;
-    }
-
-    return false;
-}
-
-bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint)
-{
-    return false;
-}
-
-Protocols::InteractionModel::Status CheckEventSupportStatus(const ConcreteEventPath & aPath)
-{
-    return Protocols::InteractionModel::Status::Success;
-}
-
-const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aConcreteClusterPath)
-{
-    // Note: This test does not make use of the real attribute metadata.
-    static EmberAfAttributeMetadata stub = { .defaultValue = EmberAfDefaultOrMinMaxAttributeValue(uint32_t(0)) };
-    return &stub;
-}
-
-CHIP_ERROR WriteSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, const ConcreteDataAttributePath & aPath,
-                                  TLV::TLVReader & aReader, WriteHandler * aWriteHandler)
-{
-    static ListIndex listStructOctetStringElementCount = 0;
-
-    if (aPath.mDataVersion.HasValue() && aPath.mDataVersion.Value() == kRejectedDataVersion)
-    {
-        return aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::DataVersionMismatch);
-    }
-
-    if (aPath.mClusterId == Clusters::UnitTesting::Id &&
-        aPath.mAttributeId == Attributes::ListStructOctetString::TypeInfo::GetAttributeId())
-    {
-        if (gWriteResponseDirective == WriteResponseDirective::kSendAttributeSuccess)
-        {
-            if (!aPath.IsListOperation() || aPath.mListOp == ConcreteDataAttributePath::ListOperation::ReplaceAll)
-            {
-
-                Attributes::ListStructOctetString::TypeInfo::DecodableType value;
-
-                ReturnErrorOnFailure(DataModel::Decode(aReader, value));
-
-                auto iter                         = value.begin();
-                listStructOctetStringElementCount = 0;
-                while (iter.Next())
-                {
-                    auto & item = iter.GetValue();
-
-                    VerifyOrReturnError(item.member1 == listStructOctetStringElementCount, CHIP_ERROR_INVALID_ARGUMENT);
-                    listStructOctetStringElementCount++;
-                }
-
-                aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success);
-            }
-            else if (aPath.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem)
-            {
-                Structs::TestListStructOctet::DecodableType item;
-                ReturnErrorOnFailure(DataModel::Decode(aReader, item));
-                VerifyOrReturnError(item.member1 == listStructOctetStringElementCount, CHIP_ERROR_INVALID_ARGUMENT);
-                listStructOctetStringElementCount++;
-
-                aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success);
-            }
-            else
-            {
-                return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
-            }
-        }
-        else
-        {
-            aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Failure);
-        }
-
-        return CHIP_NO_ERROR;
-    }
-    if (aPath.mClusterId == Clusters::UnitTesting::Id && aPath.mAttributeId == Attributes::ListFabricScoped::Id)
-    {
-        // Mock an invalid SubjectDescriptor.
-        // NOTE: completely ignores the passed-in subjectDescriptor
-        AttributeValueDecoder decoder(aReader, Access::SubjectDescriptor());
-        if (!aPath.IsListOperation() || aPath.mListOp == ConcreteDataAttributePath::ListOperation::ReplaceAll)
-        {
-            Attributes::ListFabricScoped::TypeInfo::DecodableType value;
-
-            ReturnErrorOnFailure(decoder.Decode(value));
-
-            auto iter = value.begin();
-            while (iter.Next())
-            {
-                auto & item = iter.GetValue();
-                (void) item;
-            }
-
-            aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success);
-        }
-        else if (aPath.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem)
-        {
-            Structs::TestFabricScoped::DecodableType item;
-            ReturnErrorOnFailure(decoder.Decode(item));
-
-            aWriteHandler->AddStatus(aPath, Protocols::InteractionModel::Status::Success);
-        }
-        else
-        {
-            return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
-        }
-        return CHIP_NO_ERROR;
-    }
-
-    // Boolean attribute of unit testing cluster triggers "multiple errors" case.
-    if (aPath.mClusterId == Clusters::UnitTesting::Id && aPath.mAttributeId == Attributes::Boolean::TypeInfo::GetAttributeId())
-    {
-        Protocols::InteractionModel::ClusterStatusCode status{ Protocols::InteractionModel::Status::InvalidValue };
-
-        if (gWriteResponseDirective == WriteResponseDirective::kSendMultipleSuccess)
-        {
-            status = Protocols::InteractionModel::Status::Success;
-        }
-        else if (gWriteResponseDirective == WriteResponseDirective::kSendMultipleErrors)
-        {
-            status = Protocols::InteractionModel::Status::Failure;
-        }
-        else
-        {
-            VerifyOrDie(false);
-        }
-
-        for (size_t i = 0; i < 4; ++i)
-        {
-            aWriteHandler->AddStatus(aPath, status);
-        }
-
-        return CHIP_NO_ERROR;
-    }
-
-    if (aPath.mClusterId == Clusters::UnitTesting::Id && aPath.mAttributeId == Attributes::Int8u::TypeInfo::GetAttributeId())
-    {
-        Protocols::InteractionModel::ClusterStatusCode status{ Protocols::InteractionModel::Status::InvalidValue };
-        if (gWriteResponseDirective == WriteResponseDirective::kSendClusterSpecificSuccess)
-        {
-            status = Protocols::InteractionModel::ClusterStatusCode::ClusterSpecificSuccess(kExampleClusterSpecificSuccess);
-        }
-        else if (gWriteResponseDirective == WriteResponseDirective::kSendClusterSpecificFailure)
-        {
-            status = Protocols::InteractionModel::ClusterStatusCode::ClusterSpecificFailure(kExampleClusterSpecificFailure);
-        }
-        else
-        {
-            VerifyOrDie(false);
-        }
-
-        aWriteHandler->AddStatus(aPath, status);
-        return CHIP_NO_ERROR;
-    }
-
-    return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
-}
-
 void DispatchSingleClusterCommand(const ConcreteCommandPath & aCommandPath, chip::TLV::TLVReader & aReader,
                                   CommandHandler * apCommandObj)
 {
@@ -481,24 +312,6 @@
     }
 }
 
-Protocols::InteractionModel::Status ServerClusterCommandExists(const ConcreteCommandPath & aCommandPath)
-{
-    // Mock cluster catalog, only support commands on one cluster on one endpoint.
-    using Protocols::InteractionModel::Status;
-
-    if (aCommandPath.mEndpointId != DataModelTests::kTestEndpointId)
-    {
-        return Status::UnsupportedEndpoint;
-    }
-
-    if (aCommandPath.mClusterId != Clusters::UnitTesting::Id)
-    {
-        return Status::UnsupportedCluster;
-    }
-
-    return Status::Success;
-}
-
 CustomDataModel & CustomDataModel::Instance()
 {
     static CustomDataModel model;
@@ -509,20 +322,6 @@
 {
     AttributeEncodeState mutableState(&encoder.GetState()); // provide a state copy to start.
 
-#if CHIP_CONFIG_USE_EMBER_DATA_MODEL && CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-    if ((request.path.mEndpointId < chip::Test::kMockEndpointMin) &&
-        (gReadResponseDirective == ReadResponseDirective::kSendDataResponse) &&
-        (request.path.mClusterId == app::Clusters::UnitTesting::Id) &&
-        (request.path.mAttributeId == app::Clusters::UnitTesting::Attributes::Int16u::Id))
-    {
-        // gInt16uTotalReadCount is a global that keeps changing. Further more, encoding
-        // size differs when moving from 0xFF to 0x100, so encoding sizes in TLV differ.
-        //
-        // This is a HACKISH workaround as it relies that we ember-read before datamodel-read
-        gInt16uTotalReadCount--;
-    }
-#endif // CHIP_CONFIG_USE_EMBER_DATA_MODEL && CHIP_CONFIG_USE_DATA_MODEL_INTERFACE
-
     Access::SubjectDescriptor subjectDescriptor;
     if (request.subjectDescriptor != nullptr)
     {
diff --git a/src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAccessControl.mm b/src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAccessControl.mm
index e98bdc0..35f602e 100644
--- a/src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAccessControl.mm
+++ b/src/darwin/Framework/CHIP/ServerEndpoint/MTRServerAccessControl.mm
@@ -35,7 +35,6 @@
 #include <lib/core/Global.h>
 #include <lib/core/NodeId.h>
 
-#include <app/util/ember-compatibility-functions.h>
 #include <app/util/privilege-storage.h>
 
 using namespace chip;
@@ -47,7 +46,14 @@
 public:
     bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint) override
     {
-        return app::IsDeviceTypeOnEndpoint(deviceType, endpoint);
+        app::DataModel::Provider * model = app::InteractionModelEngine::GetInstance()->GetDataModelProvider();
+
+        for (auto type = model->FirstDeviceType(endpoint); type.has_value(); type = model->NextDeviceType(endpoint, *type)) {
+            if (type->deviceTypeId == deviceType) {
+                return true;
+            }
+        }
+        return false;
     }
 };
 
diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj
index 7893475..195dd8e 100644
--- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj
+++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj
@@ -161,8 +161,6 @@
 		5143851E2A65885500EDC8E6 /* MTRSwiftPairingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5143851D2A65885500EDC8E6 /* MTRSwiftPairingTests.swift */; };
 		514654492A72F9DF00904E61 /* MTRDemuxingStorage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 514654482A72F9DF00904E61 /* MTRDemuxingStorage.mm */; };
 		5146544B2A72F9F500904E61 /* MTRDemuxingStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 5146544A2A72F9F500904E61 /* MTRDemuxingStorage.h */; };
-		514C79ED2B62ADCD00DD6D7B /* ember-compatibility-functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 514C79EC2B62ADCD00DD6D7B /* ember-compatibility-functions.cpp */; };
-		514C79EE2B62ADCD00DD6D7B /* ember-compatibility-functions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 514C79EC2B62ADCD00DD6D7B /* ember-compatibility-functions.cpp */; };
 		514C79F02B62ADDA00DD6D7B /* descriptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 514C79EF2B62ADDA00DD6D7B /* descriptor.cpp */; };
 		514C79F12B62ADDA00DD6D7B /* descriptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 514C79EF2B62ADDA00DD6D7B /* descriptor.cpp */; };
 		514C79F32B62ED5500DD6D7B /* attribute-storage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 514C79F22B62ED5500DD6D7B /* attribute-storage.cpp */; };
@@ -641,7 +639,6 @@
 		5143851D2A65885500EDC8E6 /* MTRSwiftPairingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MTRSwiftPairingTests.swift; sourceTree = "<group>"; };
 		514654482A72F9DF00904E61 /* MTRDemuxingStorage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDemuxingStorage.mm; sourceTree = "<group>"; };
 		5146544A2A72F9F500904E61 /* MTRDemuxingStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRDemuxingStorage.h; sourceTree = "<group>"; };
-		514C79EC2B62ADCD00DD6D7B /* ember-compatibility-functions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ember-compatibility-functions.cpp"; path = "util/ember-compatibility-functions.cpp"; sourceTree = "<group>"; };
 		514C79EF2B62ADDA00DD6D7B /* descriptor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = descriptor.cpp; path = clusters/descriptor/descriptor.cpp; sourceTree = "<group>"; };
 		514C79F22B62ED5500DD6D7B /* attribute-storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "attribute-storage.cpp"; path = "util/attribute-storage.cpp"; sourceTree = "<group>"; };
 		514C79F52B62F0B900DD6D7B /* util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = util.cpp; path = util/util.cpp; sourceTree = "<group>"; };
@@ -1162,7 +1159,6 @@
 				5143041F2914CED9004DC7FE /* generic-callback-stubs.cpp */,
 				514C79F22B62ED5500DD6D7B /* attribute-storage.cpp */,
 				514C79EF2B62ADDA00DD6D7B /* descriptor.cpp */,
-				514C79EC2B62ADCD00DD6D7B /* ember-compatibility-functions.cpp */,
 				E04AC67C2BEEA17F00BA409B /* ember-global-attribute-access-interface.cpp */,
 				E04AC67B2BEEA17F00BA409B /* ember-io-storage.cpp */,
 				516415FE2B6B132200D5CE11 /* DataModelHandler.cpp */,
@@ -2102,7 +2098,6 @@
 				039546A62991E151006D42A8 /* InteractionModel.cpp in Sources */,
 				B4FCD5722B603A6300832859 /* DownloadLogCommand.mm in Sources */,
 				75A202E62BA8DBAC00A771DD /* reporting.cpp in Sources */,
-				514C79EE2B62ADCD00DD6D7B /* ember-compatibility-functions.cpp in Sources */,
 				039145E82993179300257B3E /* GetCommissionerNodeIdCommand.mm in Sources */,
 				0395469F2991DFC5006D42A8 /* json_reader.cpp in Sources */,
 				514C79F42B62ED5500DD6D7B /* attribute-storage.cpp in Sources */,
@@ -2178,7 +2173,6 @@
 				516415FF2B6B132200D5CE11 /* DataModelHandler.cpp in Sources */,
 				75139A6F2B7FE5E900E3A919 /* MTRDeviceControllerLocalTestStorage.mm in Sources */,
 				51E95DFC2A78443C00A434F0 /* MTRSessionResumptionStorageBridge.mm in Sources */,
-				514C79ED2B62ADCD00DD6D7B /* ember-compatibility-functions.cpp in Sources */,
 				7534F12828BFF20300390851 /* MTRDeviceAttestationDelegate.mm in Sources */,
 				B4C8E6B72B3453AD00FCD54D /* MTRDiagnosticLogsDownloader.mm in Sources */,
 				2C5EEEF7268A85C400CAE3D3 /* MTRDeviceConnectionBridge.mm in Sources */,