diff --git a/db/docs/audit_events_instance_external_streaming_destinations.yml b/db/docs/audit_events_instance_external_streaming_destinations.yml
new file mode 100644
index 0000000000000000000000000000000000000000..966e89284462b317880d60f0c940e12acfcb1b83
--- /dev/null
+++ b/db/docs/audit_events_instance_external_streaming_destinations.yml
@@ -0,0 +1,10 @@
+---
+table_name: audit_events_instance_external_streaming_destinations
+classes:
+- AuditEvents::Instance::ExternalStreamingDestination
+feature_categories:
+- audit_events
+description: Stores external audit event destinations configurations for instance.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141739
+milestone: '16.9'
+gitlab_schema: gitlab_main_clusterwide
diff --git a/db/migrate/20240130162148_create_audit_events_instance_external_streaming_destinations.rb b/db/migrate/20240130162148_create_audit_events_instance_external_streaming_destinations.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2f1d906767726afc68c3b82782a8c9bb7f7c172f
--- /dev/null
+++ b/db/migrate/20240130162148_create_audit_events_instance_external_streaming_destinations.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class CreateAuditEventsInstanceExternalStreamingDestinations < Gitlab::Database::Migration[2.2]
+  milestone '16.9'
+
+  def change
+    create_table :audit_events_instance_external_streaming_destinations do |t|
+      t.timestamps_with_timezone null: false
+      t.integer :type, null: false, limit: 2
+      t.text :name, null: false, limit: 72
+      t.jsonb :config, null: false
+      t.binary :encrypted_secret_token, null: false
+      t.binary :encrypted_secret_token_iv, null: false
+    end
+  end
+end
diff --git a/db/schema_migrations/20240130162148 b/db/schema_migrations/20240130162148
new file mode 100644
index 0000000000000000000000000000000000000000..593bb247644f0a81c4f05d93e8493da44fa47417
--- /dev/null
+++ b/db/schema_migrations/20240130162148
@@ -0,0 +1 @@
+37166b2aa9addf6d1effd34da3242866a13c9a24636f0be677d72c89bc09376d
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index bf51d637ab1697dd4c4d51ca6af923b39203f62f..456d47abb8d3e903dcbdd600f2ad88210305a418 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -13222,6 +13222,27 @@ CREATE SEQUENCE audit_events_instance_external_audit_event_destinations_id_seq
 
 ALTER SEQUENCE audit_events_instance_external_audit_event_destinations_id_seq OWNED BY audit_events_instance_external_audit_event_destinations.id;
 
+CREATE TABLE audit_events_instance_external_streaming_destinations (
+    id bigint NOT NULL,
+    created_at timestamp with time zone NOT NULL,
+    updated_at timestamp with time zone NOT NULL,
+    type smallint NOT NULL,
+    name text NOT NULL,
+    config jsonb NOT NULL,
+    encrypted_secret_token bytea NOT NULL,
+    encrypted_secret_token_iv bytea NOT NULL,
+    CONSTRAINT check_219decfb51 CHECK ((char_length(name) <= 72))
+);
+
+CREATE SEQUENCE audit_events_instance_external_streaming_destinations_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MINVALUE
+    NO MAXVALUE
+    CACHE 1;
+
+ALTER SEQUENCE audit_events_instance_external_streaming_destinations_id_seq OWNED BY audit_events_instance_external_streaming_destinations.id;
+
 CREATE TABLE audit_events_instance_google_cloud_logging_configurations (
     id bigint NOT NULL,
     created_at timestamp with time zone NOT NULL,
@@ -27021,6 +27042,8 @@ ALTER TABLE ONLY audit_events_instance_amazon_s3_configurations ALTER COLUMN id
 
 ALTER TABLE ONLY audit_events_instance_external_audit_event_destinations ALTER COLUMN id SET DEFAULT nextval('audit_events_instance_external_audit_event_destinations_id_seq'::regclass);
 
+ALTER TABLE ONLY audit_events_instance_external_streaming_destinations ALTER COLUMN id SET DEFAULT nextval('audit_events_instance_external_streaming_destinations_id_seq'::regclass);
+
 ALTER TABLE ONLY audit_events_instance_google_cloud_logging_configurations ALTER COLUMN id SET DEFAULT nextval('audit_events_instance_google_cloud_logging_configuration_id_seq'::regclass);
 
 ALTER TABLE ONLY audit_events_streaming_event_type_filters ALTER COLUMN id SET DEFAULT nextval('audit_events_streaming_event_type_filters_id_seq'::regclass);
@@ -28994,6 +29017,9 @@ ALTER TABLE ONLY audit_events_instance_amazon_s3_configurations
 ALTER TABLE ONLY audit_events_instance_external_audit_event_destinations
     ADD CONSTRAINT audit_events_instance_external_audit_event_destinations_pkey PRIMARY KEY (id);
 
+ALTER TABLE ONLY audit_events_instance_external_streaming_destinations
+    ADD CONSTRAINT audit_events_instance_external_streaming_destinations_pkey PRIMARY KEY (id);
+
 ALTER TABLE ONLY audit_events_instance_google_cloud_logging_configurations
     ADD CONSTRAINT audit_events_instance_google_cloud_logging_configurations_pkey PRIMARY KEY (id);
 
diff --git a/ee/app/models/audit_events/instance/external_streaming_destination.rb b/ee/app/models/audit_events/instance/external_streaming_destination.rb
new file mode 100644
index 0000000000000000000000000000000000000000..070dda144eb61be58d0ac38ff7366c25cd1d492a
--- /dev/null
+++ b/ee/app/models/audit_events/instance/external_streaming_destination.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module AuditEvents
+  module Instance
+    class ExternalStreamingDestination < ApplicationRecord
+      include Limitable
+      include ExternallyStreamable
+
+      self.limit_name = 'external_audit_event_destinations'
+      self.limit_scope = Limitable::GLOBAL_SCOPE
+      self.table_name = 'audit_events_instance_external_streaming_destinations'
+
+      validates :name, uniqueness: true
+    end
+  end
+end
diff --git a/ee/spec/factories/audit_events/audit_events_instance_external_streaming_destination.rb b/ee/spec/factories/audit_events/audit_events_instance_external_streaming_destination.rb
new file mode 100644
index 0000000000000000000000000000000000000000..67d38cf0270560291a167015991c800bfbdf655d
--- /dev/null
+++ b/ee/spec/factories/audit_events/audit_events_instance_external_streaming_destination.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+  factory :audit_events_instance_external_streaming_destination,
+    class: 'AuditEvents::Instance::ExternalStreamingDestination' do
+    type { 'http' }
+    config { { url: 'https://www.example.com' } }
+    secret_token { 'hello' }
+  end
+end
diff --git a/ee/spec/models/audit_events/instance/external_streaming_destination_spec.rb b/ee/spec/models/audit_events/instance/external_streaming_destination_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1dd38cfac869843b0c68ea1d449e64487081b230
--- /dev/null
+++ b/ee/spec/models/audit_events/instance/external_streaming_destination_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe AuditEvents::Instance::ExternalStreamingDestination, feature_category: :audit_events do
+  subject(:destination) { build(:audit_events_instance_external_streaming_destination) }
+
+  describe 'Validations' do
+    it 'validates uniqueness of name scoped to namespace' do
+      create(:audit_events_instance_external_streaming_destination, name: 'Test Destination')
+      destination = build(:audit_events_instance_external_streaming_destination, name: 'Test Destination')
+
+      expect(destination).not_to be_valid
+      expect(destination.errors.full_messages).to include('Name has already been taken')
+    end
+  end
+
+  it_behaves_like 'includes Limitable concern' do
+    subject { build(:audit_events_instance_external_streaming_destination) }
+  end
+
+  it_behaves_like 'includes ExternallyStreamable concern' do
+    subject { build(:audit_events_instance_external_streaming_destination) }
+
+    let(:model_factory_name) { :audit_events_instance_external_streaming_destination }
+  end
+end