diff --git a/config/feature_flags/development/expired_storage_check.yml b/config/feature_flags/development/expired_storage_check.yml
new file mode 100644
index 0000000000000000000000000000000000000000..271cc951f1fb81338cd4239fd5430c3897124107
--- /dev/null
+++ b/config/feature_flags/development/expired_storage_check.yml
@@ -0,0 +1,8 @@
+---
+name: expired_storage_check
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121048
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/411919
+milestone: '16.1'
+type: development
+group: group::utilization
+default_enabled: false
diff --git a/ee/app/models/ee/namespace.rb b/ee/app/models/ee/namespace.rb
index caaa65ef7a6b9611bd28cc6054055cdb10fbb016..0d3a84b38f9519367578b0f34a33c69663b92849 100644
--- a/ee/app/models/ee/namespace.rb
+++ b/ee/app/models/ee/namespace.rb
@@ -83,11 +83,17 @@ module Namespace
         where("EXISTS (?)", matcher)
       end
 
-      delegate :additional_purchased_storage_size, :additional_purchased_storage_size=,
+      delegate :eligible_additional_purchased_storage_size, :additional_purchased_storage_size=,
         :additional_purchased_storage_ends_on, :additional_purchased_storage_ends_on=,
         :temporary_storage_increase_ends_on, :temporary_storage_increase_ends_on=,
         to: :namespace_limit, allow_nil: true
 
+      # `eligible_additional_purchased_storage_size` uses a FF to start checking `additional_purchased_storage_ends_on`
+      # if the FF is enabled before returning `additional_purchased_storage_size`
+      # To minimize the footprint of the change, aliasing namespace.additional_purchased_storage_size
+      # to namespace.eligible_additional_purchased_storage_size
+      alias_method :additional_purchased_storage_size, :eligible_additional_purchased_storage_size
+
       delegate :email, to: :owner, allow_nil: true, prefix: true
 
       # Opportunistically clear the +file_template_project_id+ if invalid
diff --git a/ee/app/models/namespace_limit.rb b/ee/app/models/namespace_limit.rb
index 3d1e630d0cae0cc81f8b9ed23b8ccc3d35c203dc..9b0560106c637cf5a1de43912a9adf5a10823375 100644
--- a/ee/app/models/namespace_limit.rb
+++ b/ee/app/models/namespace_limit.rb
@@ -26,6 +26,16 @@ def eligible_for_temporary_storage_increase?
     namespace.root_storage_size.usage_ratio >= MIN_REQURIED_STORAGE_USAGE_RATIO
   end
 
+  def eligible_additional_purchased_storage_size
+    if Feature.enabled?(:expired_storage_check, namespace) &&
+        additional_purchased_storage_ends_on &&
+        Date.today > additional_purchased_storage_ends_on
+      0
+    else
+      additional_purchased_storage_size
+    end
+  end
+
   private
 
   def namespace_is_root_namespace
diff --git a/ee/spec/models/ee/namespace_spec.rb b/ee/spec/models/ee/namespace_spec.rb
index 3999051e2fee6572161e1c091ff5b12b12eb052f..65416e23ddc6d60a7cb062f6eeec9efd15a96167 100644
--- a/ee/spec/models/ee/namespace_spec.rb
+++ b/ee/spec/models/ee/namespace_spec.rb
@@ -25,7 +25,6 @@
   it { is_expected.to delegate_method(:upgradable?).to(:gitlab_subscription) }
   it { is_expected.to delegate_method(:trial_extended_or_reactivated?).to(:gitlab_subscription) }
   it { is_expected.to delegate_method(:email).to(:owner).with_prefix.allow_nil }
-  it { is_expected.to delegate_method(:additional_purchased_storage_size).to(:namespace_limit) }
   it { is_expected.to delegate_method(:additional_purchased_storage_size=).to(:namespace_limit).with_arguments(:args) }
   it { is_expected.to delegate_method(:additional_purchased_storage_ends_on).to(:namespace_limit) }
   it { is_expected.to delegate_method(:additional_purchased_storage_ends_on=).to(:namespace_limit).with_arguments(:args) }
@@ -1304,6 +1303,13 @@
     end
   end
 
+  describe '#additional_purchased_storage_size' do
+    it 'calls namespace_limit#eligible_additional_purchased_storage_size' do
+      expect(namespace.namespace_limit).to receive(:eligible_additional_purchased_storage_size)
+      namespace.additional_purchased_storage_size
+    end
+  end
+
   describe '#contains_locked_projects?' do
     using RSpec::Parameterized::TableSyntax
 
diff --git a/ee/spec/models/namespace_limit_spec.rb b/ee/spec/models/namespace_limit_spec.rb
index 6fcc2e468faeef9fa060c8fb1db820bbca651ab9..0c5722a71b6e54d116f4c0ea6f3c17b192334697 100644
--- a/ee/spec/models/namespace_limit_spec.rb
+++ b/ee/spec/models/namespace_limit_spec.rb
@@ -95,6 +95,63 @@
     end
   end
 
+  describe '#eligible_additional_purchased_storage_size' do
+    subject { namespace_limit.eligible_additional_purchased_storage_size }
+
+    before do
+      allow(namespace_limit).to receive(:additional_purchased_storage_size)
+        .and_return(10)
+    end
+
+    context 'with expired_storage_check ff enabled' do
+      before do
+        stub_feature_flags(expired_storage_check: true)
+      end
+
+      context 'with expired storage' do
+        before do
+          allow(namespace_limit).to receive(:additional_purchased_storage_ends_on)
+            .and_return(Date.yesterday)
+        end
+
+        it { is_expected.to eq(0) }
+      end
+
+      context 'with valid storage' do
+        before do
+          allow(namespace_limit).to receive(:additional_purchased_storage_ends_on)
+            .and_return(Date.tomorrow)
+        end
+
+        it { is_expected.to eq(10) }
+      end
+    end
+
+    context 'with expired_storage_check ff disabled' do
+      before do
+        stub_feature_flags(expired_storage_check: false)
+      end
+
+      context 'with expired storage' do
+        before do
+          allow(namespace_limit).to receive(:additional_purchased_storage_ends_on)
+            .and_return(Date.yesterday)
+        end
+
+        it { is_expected.to eq(10) }
+      end
+
+      context 'with valid storage' do
+        before do
+          allow(namespace_limit).to receive(:additional_purchased_storage_ends_on)
+            .and_return(Date.tomorrow)
+        end
+
+        it { is_expected.to eq(10) }
+      end
+    end
+  end
+
   describe 'validations' do
     it { is_expected.to validate_presence_of(:namespace) }