diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8f6ab36..2f401c9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,8 @@
  - Multi period support for DASH
    (https://github.com/google/shaka-streamer/issues/43)
    (https://github.com/google/shaka-streamer/pull/78)
+ - Add LL-DASH support
+   (https://github.com/google/shaka-streamer/pull/88)
 
 
 ## 0.4.0 (2021-08-26)
diff --git a/config_files/pipeline_low_latency_dash_config.yaml b/config_files/pipeline_low_latency_dash_config.yaml
new file mode 100644
index 0000000..6a93699
--- /dev/null
+++ b/config_files/pipeline_low_latency_dash_config.yaml
@@ -0,0 +1,58 @@
+# Copyright 2019 Google LLC
+#
+# 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
+#
+#     https://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.
+
+# This is a sample pipeline configuration file for Shaka Streamer in live mode.
+# Here you configure resolutions, manifest formats, segment size, and more.
+
+# Streaming mode.  Can be live or vod.
+streaming_mode: live
+
+# A list of resolutions to encode.
+resolutions:
+  - 720p
+  - 480p
+
+# A list of channel layouts to encode.
+channel_layouts:
+  - stereo
+
+# The codecs to encode with.
+audio_codecs:
+  - aac
+video_codecs:
+  - h264
+
+# Manifest format must be DASH for LL-DASH streaming
+manifest_format:
+  - dash
+
+# Length of each segment in seconds.
+segment_size: 2
+
+# Availability window, or the number of seconds a segment remains available.
+availability_window: 300
+
+# Presentation delay, or how far back from the edge the player should be.
+presentation_delay: 0
+
+# Update period, or how often the player should fetch a new manifest.
+update_period: 8
+
+# Stream in low latency dash mode, or chunked 
+low_latency_dash_mode: True
+
+# UTC timing values, or the global timing source used for segment time stamps.
+utc_timings:
+ - scheme_id_uri: urn:mpeg:dash:utc:http-xsdate:2014
+   value: https://akamai.com/?.iso
\ No newline at end of file
diff --git a/run_end_to_end_tests.py b/run_end_to_end_tests.py
index 238d16f..ef99654 100755
--- a/run_end_to_end_tests.py
+++ b/run_end_to_end_tests.py
@@ -91,9 +91,17 @@ def dashStreamsReady(manifest_path):
   pattern = re.compile(r'<Representation.*?((\n).*?)*?Representation>')
   with open(manifest_path) as manifest_file:
     for representation in pattern.finditer(manifest_file.read()):
-      if not re.search(r'<S t', representation.group()):
-        # This Representation has no segments.
-        return False
+      if controller.is_low_latency_dash_mode():
+        # LL-DASH manifests do not contain the segment reference tag <S>.
+        # Check for the availabilityTimeOffset attribute instead.
+        if not re.search(r'availabilityTimeOffset', representation.group()):
+          # This Representation does not have a availabilityTimeOffset yet,
+          # meaning the first chunk is not yet ready for playout.
+          return False
+      else:
+        if not re.search(r'<S t', representation.group()):
+          # This Representation has no segments.
+          return False
 
   return True
 
diff --git a/streamer/controller_node.py b/streamer/controller_node.py
index 1af064d..cb30bc4 100644
--- a/streamer/controller_node.py
+++ b/streamer/controller_node.py
@@ -36,7 +36,7 @@
 from streamer.node_base import NodeBase, ProcessStatus
 from streamer.output_stream import AudioOutputStream, OutputStream, TextOutputStream, VideoOutputStream
 from streamer.packager_node import PackagerNode
-from streamer.pipeline_configuration import PipelineConfig, StreamingMode
+from streamer.pipeline_configuration import ManifestFormat, PipelineConfig, StreamingMode
 from streamer.transcoder_node import TranscoderNode
 from streamer.periodconcat_node import PeriodConcatNode
 import streamer.subprocessWindowsPatch  # side-effects only
@@ -143,6 +143,17 @@ def start(self, output_location: str,
         raise RuntimeError(
             'Multiperiod input list support is incompatible with HTTP outputs.')
 
+    if self._pipeline_config.low_latency_dash_mode:
+      # Check some restrictions on LL-DASH packaging.
+      if ManifestFormat.DASH not in self._pipeline_config.manifest_format:
+        raise RuntimeError(
+            'low_latency_dash_mode is only compatible with DASH ouputs. ' +
+            'manifest_format must include DASH')
+
+      if not self._pipeline_config.utc_timings:
+        raise RuntimeError(
+            'For low_latency_dash_mode, the utc_timings must be set.')
+
     # Note that we remove the trailing slash from the output location, because
     # otherwise GCS would create a subdirectory whose name is "".
     output_location = output_location.rstrip('/')
@@ -289,6 +300,14 @@ def is_vod(self) -> bool:
 
     return self._pipeline_config.streaming_mode == StreamingMode.VOD
 
+  def is_low_latency_dash_mode(self) -> bool:
+    """Returns True if the pipeline is running in LL-DASH mode.
+
+    :rtype: bool
+    """
+
+    return self._pipeline_config.low_latency_dash_mode
+
 class VersionError(Exception):
   """A version error for one of Shaka Streamer's external dependencies.
 
diff --git a/streamer/packager_node.py b/streamer/packager_node.py
index 49006bb..86e8c09 100644
--- a/streamer/packager_node.py
+++ b/streamer/packager_node.py
@@ -160,6 +160,16 @@ def _setup_stream(self, stream: OutputStream) -> str:
   def _setup_manifest_format(self) -> List[str]:
     args: List[str] = []
     if ManifestFormat.DASH in self._pipeline_config.manifest_format:
+      if self._pipeline_config.utc_timings:
+        args += [
+            '--utc_timings',
+            ','.join(timing.scheme_id_uri + '=' +
+                     timing.value for timing in self._pipeline_config.utc_timings)
+        ]
+      if self._pipeline_config.low_latency_dash_mode:
+        args += [
+            '--low_latency_dash_mode=true',
+        ]
       if self._pipeline_config.streaming_mode == StreamingMode.VOD:
         args += [
             '--generate_static_live_mpd',
diff --git a/streamer/pipeline_configuration.py b/streamer/pipeline_configuration.py
index 72379ab..8ce8aba 100644
--- a/streamer/pipeline_configuration.py
+++ b/streamer/pipeline_configuration.py
@@ -76,6 +76,17 @@ class EncryptionMode(enum.Enum):
   RAW = 'raw'
   """Raw key mode"""
 
+class UtcTimingPair(configuration.Base):
+  """An object containing the attributes for a DASH MPD UTCTiming 
+  element"""
+
+  # TODO: Use an enum for scheme_id_uri to simplify the config input
+  scheme_id_uri = configuration.Field(str).cast()
+  """SchemeIdUri attribute to be used for the UTCTiming element"""
+
+  value = configuration.Field(str).cast()
+  """Value attribute to be used for the UTCTiming element"""
+
 class RawKeyConfig(configuration.Base):
   """An object representing a list of keys for Raw key encryption"""
 
@@ -309,6 +320,19 @@ class PipelineConfig(configuration.Base):
                                    default=EncryptionConfig({})).cast()
   """Encryption settings."""
 
+  # TODO: Generalize this to low_latency_mode once LL-HLS is supported by Packager
+  low_latency_dash_mode = configuration.Field(bool, default=False).cast()
+  """If true, stream in low latency mode for DASH."""
+
+  utc_timings = configuration.Field(List[UtcTimingPair]).cast()
+  """UTCTiming schemeIdUri and value pairs for the DASH MPD.
+
+  If multiple UTCTiming pairs are provided for redundancy,
+  list the pairs in the order of preference.
+
+  Must be set for LL-DASH streaming.
+  """
+
 
   def __init__(self, *args) -> None:
 
diff --git a/tests/tests.js b/tests/tests.js
index fbf66eb..a507c1e 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -147,6 +147,8 @@ describe('Shaka Streamer', () => {
   muxedTextTests(dashManifestUrl, '(dash)');
 
   multiPeriodTests(dashManifestUrl, '(dash)');
+
+  lowLatencyDashTests(dashManifestUrl, '(dash)');
 });
 
 function errorTests() {
@@ -378,6 +380,39 @@ function errorTests() {
           error_type: 'RuntimeError',
         }));
   });
+
+  it('fails when utc_timing is not set for low_latency_dash_mode', async () => {
+    const inputConfig = getBasicInputConfig();
+    const pipelineConfig = {
+      low_latency_dash_mode: true,
+      streaming_mode: 'live',
+    };
+
+    await expectAsync(startStreamer(inputConfig, pipelineConfig))
+        .toBeRejectedWith(jasmine.objectContaining({
+          error_type: 'RuntimeError',
+        }));
+  });
+
+  it('fails when low_latency_dash_mode is set without a DASH manifest', async () => {
+    const inputConfig = getBasicInputConfig();
+    const pipelineConfig = {
+      low_latency_dash_mode: true,
+      manifest_format: ['hls'],
+      streaming_mode: 'live',
+      utc_timings: [
+        {
+          scheme_id_uri:'urn:mpeg:dash:utc:http-xsdate:2014',
+          value:'https://time.akamai.com/?.iso'
+        },
+      ],
+    };
+
+    await expectAsync(startStreamer(inputConfig, pipelineConfig))
+        .toBeRejectedWith(jasmine.objectContaining({
+          error_type: 'RuntimeError',
+        }));
+  });
 }
 
 function resolutionTests(manifestUrl, format) {
@@ -1397,3 +1432,43 @@ function multiPeriodTests(manifestUrl, format) {
     expect(video.duration).toBeGreaterThan(1.9);
   });
 }
+
+function lowLatencyDashTests(manifestUrl, format) {
+  it('can process LL-DASH streaming ' + format, async() => {
+    const inputConfigDict = {
+      'inputs': [
+        {
+          'name': TEST_DIR + 'BigBuckBunny.1080p.mp4',
+          'media_type': 'video',
+          // Keep this test short by only encoding 4s of content.
+          'end_time': '0:04',
+        }
+      ],
+    };
+    const pipelineConfigDict = {
+      'streaming_mode': 'live',
+      'resolutions': ['144p'],
+      'video_codecs': ['h264'],
+      'manifest_format': ['dash'],
+      'segment_size': 2,
+      'low_latency_dash_mode': true,
+      'utc_timings': [
+        {
+          'scheme_id_uri':'urn:mpeg:dash:utc:http-xsdate:2014',
+          'value':'https://time.akamai.com/?.iso'
+        },
+      ],
+    };
+    await startStreamer(inputConfigDict, pipelineConfigDict);
+
+    // TODO(CaitlinO'Callaghan): fix so player loads and test passes
+    player.configure({
+      streaming: {
+        lowLatencyMode: true,
+        inaccurateManifestTolerance: 0,
+        rebufferingGoal: 0.01,
+      }
+    });
+    await player.load(manifestUrl);
+  });
+}